Update 0.3 docs

docs
Alinson S. Xavier 2 years ago
parent 3d4a6a87a8
commit d9d44ce4b2
Signed by: isoron
GPG Key ID: 0DA8E4B9E1109DCA

1
.gitignore vendored

@ -0,0 +1 @@
.nfs*

@ -1,4 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 2d7b5c0d06fd9875399c14b694147ac6
config: f1eab20ae8c8d57432d1dbf183c11c00
tags: d77d1c0d9ca2f4c8421862c7c5a0d620

@ -25,18 +25,18 @@ miplearn.collectors.basic
:undoc-members:
:show-inheritance:
miplearn.features.fields
------------------------
miplearn.extractors.fields
--------------------------
.. automodule:: miplearn.features.fields
.. automodule:: miplearn.extractors.fields
:members:
:undoc-members:
:show-inheritance:
miplearn.features.AlvLouWeh2017
-------------------------------
miplearn.extractors.AlvLouWeh2017
---------------------------------
.. automodule:: miplearn.features.AlvLouWeh2017
.. automodule:: miplearn.extractors.AlvLouWeh2017
:members:
:undoc-members:
:show-inheritance:

@ -38,7 +38,10 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
@ -95,20 +98,20 @@
" print(\"x3 =\", h5.get_array(\"x3\"))\n",
" print(\"x4 =\", h5.get_array(\"x4\"))\n",
" print(\"x5 =\", h5.get_sparse(\"x5\"))"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"source": [],
"metadata": {
"collapsed": false
}
},
"source": []
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"## Basic collector\n",
"\n",
@ -121,13 +124,13 @@
"Data extracted in Phases 1, 2 and 3 above are prefixed, respectively as `static_`, `lp_` and `mip_`. The entire set of fields is shown in the table below.\n",
"\n",
"[BasicCollector]: ../../api/collectors/#miplearn.collectors.basic.BasicCollector\n"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"### Data fields\n",
"\n",
@ -161,39 +164,30 @@
"| `mip_obj_value` | `float` | Value of the best MIP solution |\n",
"| `mip_var_values` | `(nvars,)` | Best MIP solution |\n",
"| `mip_wallclock_time` | `float` | Time taken to solve the MIP (in seconds) |"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"### Example\n",
"\n",
"The example below shows how to generate a few random instances of the traveling salesman problem, store its problem data, run the collector and print some of the training data to screen."
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "code",
"execution_count": 2,
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/axavier/Software/anaconda3/envs/miplearn/lib/python3.8/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n"
]
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Removing empty/corrupted h5 file: data/tsp/00000.h5\n",
"lp_obj_value = 2909.0\n",
"mip_obj_value = 2921.0\n"
]
@ -209,7 +203,7 @@
" TravelingSalesmanGenerator,\n",
" build_tsp_model,\n",
")\n",
"from miplearn.io import save\n",
"from miplearn.io import write_pkl_gz\n",
"from miplearn.h5 import H5File\n",
"from miplearn.collectors.basic import BasicCollector\n",
"\n",
@ -228,30 +222,27 @@
").generate(10)\n",
"\n",
"# Save instance data to data/tsp/00000.pkl.gz, data/tsp/00001.pkl.gz, ...\n",
"save(data, \"data/tsp\")\n",
"write_pkl_gz(data, \"data/tsp\")\n",
"\n",
"# Solve all instances and collect basic solution information. Process at most four\n",
"# instances in parallel, with a per-instance time limit of one hour.\n",
"bc = BasicCollector(time_limit_sec=3600)\n",
"# Solve all instances and collect basic solution information.\n",
"# Process at most four instances in parallel.\n",
"bc = BasicCollector()\n",
"bc.collect(glob(\"data/tsp/*.pkl.gz\"), build_tsp_model, n_jobs=4)\n",
"\n",
"# Read and print some training data for the first instance.\n",
"with H5File(\"data/tsp/00000.h5\", \"r\") as h5:\n",
" print(\"lp_obj_value = \", h5.get_scalar(\"lp_obj_value\"))\n",
" print(\"mip_obj_value = \", h5.get_scalar(\"mip_obj_value\"))"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "code",
"execution_count": 2,
"outputs": [],
"source": [],
"execution_count": null,
"metadata": {
"collapsed": false
}
},
"outputs": [],
"source": []
}
],
"metadata": {
@ -270,7 +261,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.13"
"version": "3.9.12"
}
},
"nbformat": 4,

@ -12,6 +12,9 @@
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"\n",
"## Overview\n",
@ -24,37 +27,37 @@
"\n",
"[FeatureExtractor]: ../../api/collectors/#miplearn.features.fields.FeaturesExtractor\n",
"[H5File]: ../../api/helpers/#miplearn.h5.H5File"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"\n",
"## H5FieldsExtractor\n",
"\n",
"[H5FieldsExtractor][H5FieldsExtractor], the most simple extractor in MIPLearn, simple extracts data that is already available in the HDF5 file, assembles it into a matrix and returns it as-is. The fields used to build instance, variable and constraint features are user-specified. The class also performs checks to ensure that the shapes of the returned matrices make sense."
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"### Example\n",
"\n",
"The example below demonstrates the usage of H5FieldsExtractor in a randomly generated instance of the multi-dimensional knapsack problem."
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
@ -92,12 +95,12 @@
"from scipy.stats import uniform, randint\n",
"\n",
"from miplearn.collectors.basic import BasicCollector\n",
"from miplearn.features.fields import H5FieldsExtractor\n",
"from miplearn.extractors.fields import H5FieldsExtractor\n",
"from miplearn.h5 import H5File\n",
"from miplearn.io import save\n",
"from miplearn.io import write_pkl_gz\n",
"from miplearn.problems.multiknapsack import (\n",
" MultiKnapsackGenerator,\n",
" build_multiknapsack_model\n",
" build_multiknapsack_model,\n",
")\n",
"\n",
"# Set random seed to make example reproducible\n",
@ -105,7 +108,7 @@
"\n",
"# Generate some random multiknapsack instances\n",
"rmtree(\"data/multiknapsack/\", ignore_errors=True)\n",
"save(\n",
"write_pkl_gz(\n",
" MultiKnapsackGenerator(\n",
" n=randint(low=10, high=11),\n",
" m=randint(low=5, high=6),\n",
@ -117,7 +120,7 @@
" p_jitter=uniform(loc=0.75, scale=0.5),\n",
" fix_w=True,\n",
" ).generate(10),\n",
" \"data/multiknapsack\"\n",
" \"data/multiknapsack\",\n",
")\n",
"\n",
"# Run the basic collector\n",
@ -148,7 +151,7 @@
" \"static_constr_rhs\",\n",
" \"lp_constr_dual_values\",\n",
" \"lp_constr_slacks\",\n",
" ]\n",
" ],\n",
")\n",
"\n",
"with H5File(\"data/multiknapsack/00000.h5\") as h5:\n",
@ -163,50 +166,50 @@
" # Extract and print constraint features\n",
" x3 = ext.get_constr_features(h5)\n",
" print(\"constraint features\", x3.shape, \"\\n\", x3)\n"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"\n",
"[H5FieldsExtractor]: ../../api/collectors/#miplearn.features.fields.H5FieldsExtractor"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"<div class=\"alert alert-warning\">\n",
"Warning\n",
"\n",
"You should ensure that the number of features remains the same for all relevant HDF5 files. In the previous example, to illustrate this issue, we used variable objective coefficients as instance features. While this is allowed, note that this requires all problem instances to have the same number of variables; otherwise the number of features would vary from instance to instance and MIPLearn would be unable to concatenate the matrices.\n",
"</div>"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"## AlvLouWeh2017Extractor\n",
"\n",
"Alvarez, Louveaux and Wehenkel (2017) proposed a set features to describe a particular decision variable in a given node of the branch-and-bound tree, and applied it to the problem of mimicking strong branching decisions. The class [AlvLouWeh2017Extractor][] implements a subset of these features (40 out of 64), which are available outside of the branch-and-bound tree. Some features are derived from the static defintion of the problem (i.e. from objective function and constraint data), while some features are derived from the solution to the LP relaxation. The features have been designed to be: (i) independent of the size of the problem; (ii) invariant with respect to irrelevant problem transformations, such as row and column permutation; and (iii) independent of the scale of the problem. We refer to the paper for a more complete description.\n",
"\n",
"### Example"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
@ -277,7 +280,7 @@
}
],
"source": [
"from miplearn.features.AlvLouWeh2017 import AlvLouWeh2017Extractor\n",
"from miplearn.extractors.AlvLouWeh2017 import AlvLouWeh2017Extractor\n",
"from miplearn.h5 import H5File\n",
"\n",
"# Build the extractor\n",
@ -285,17 +288,16 @@
"\n",
"# Open previously-created multiknapsack training data\n",
"with H5File(\"data/multiknapsack/00000.h5\") as h5:\n",
"\n",
" # Extract and print variable features\n",
" x1 = ext.get_var_features(h5)\n",
" print(\"x1\", x1.shape, \"\\n\", x1.round(1))"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"<div class=\"alert alert-info\">\n",
"References\n",
@ -304,10 +306,7 @@
"* **Alvarez, Alejandro Marcos, Quentin Louveaux, and Louis Wehenkel.** *A machine learning-based approximation of strong branching.* INFORMS Journal on Computing 29.1 (2017): 185-195.\n",
"\n",
"</div>"
],
"metadata": {
"collapsed": false
}
]
}
],
"metadata": {
@ -326,7 +325,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.13"
"version": "3.9.12"
}
},
"nbformat": 4,

@ -60,10 +60,16 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 1,
"id": "253adbf4",
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"\n",
"from sklearn.dummy import DummyClassifier\n",
"from sklearn.neighbors import KNeighborsClassifier\n",
"\n",
@ -114,14 +120,13 @@
" extractor=H5FieldsExtractor(instance_fields=[\"static_var_obj_coeffs\"]),\n",
" constructor=MergeTopSolutions(k=3, thresholds=[0.25, 0.75]),\n",
" action=EnforceProximity(3),\n",
")"
],
"metadata": {
"collapsed": false
}
")\n"
]
},
{
"cell_type": "markdown",
"id": "f194a793",
"metadata": {},
"source": [
"## Independent vars primal component\n",
"\n",
@ -136,14 +141,18 @@
"3. To make multiple copies of the provided ML classifier, MIPLearn uses the standard `sklearn.base.clone` method, which may not be suitable for classifiers from other frameworks. To handle this, it is possible to override the clone function using the `clone_fn` constructor argument.\n",
"\n",
"### Examples"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 2,
"id": "3fc0b5d1",
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"from sklearn.linear_model import LogisticRegression\n",
@ -151,7 +160,6 @@
"from miplearn.classifiers.singleclass import SingleClassFix\n",
"from miplearn.components.primal.indep import IndependentVarsPrimalComponent\n",
"from miplearn.extractors.AlvLouWeh2017 import AlvLouWeh2017Extractor\n",
"from miplearn.solvers.learning import LearningSolver\n",
"from miplearn.components.primal.actions import SetWarmStart\n",
"\n",
"# Configures a primal component that independently predicts the value of each\n",
@ -167,14 +175,13 @@
" ),\n",
" extractor=AlvLouWeh2017Extractor(),\n",
" action=SetWarmStart(),\n",
")"
],
"metadata": {
"collapsed": false
}
")\n"
]
},
{
"cell_type": "markdown",
"id": "45107a0c",
"metadata": {},
"source": [
"## Joint vars primal component\n",
"In the previous subsection, we used multiple machine learning models to independently predict the values of the binary decision variables. When these values are correlated, an alternative approach is to jointly predict the values of all binary variables using a single machine learning model. This strategy is implemented by `JointVarsPrimalComponent`. Compared to the previous ones, this component is much more straightforwad. It simply extracts instance features, using the user-provided feature extractor, then directly trains the user-provided binary classifier (using the `fit` method), without making any copies. The trained classifier is then used to predict entire solutions (using the `predict` method), which are given to the solver using one of the previously discussed methods. In the example below, we illustrate the usage of this component with a simple feed-forward neural network.\n",
@ -182,21 +189,24 @@
"`JointVarsPrimalComponent` can also be used to implement strategies that use multiple machine learning models, but not indepedently. For example, a common strategy in multioutput prediction is building a *classifier chain*. In this approach, the first decision variable is predicted using the instance features alone; but the $n$-th decision variable is predicted using the instance features plus the predicted values of the $n-1$ previous variables. This can be easily implemented using scikit-learn's `ClassifierChain` estimator, as shown in the example below.\n",
"\n",
"### Examples"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 3,
"id": "cf9b52dd",
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"from sklearn.multioutput import ClassifierChain\n",
"from sklearn.neural_network import MLPClassifier\n",
"from miplearn.components.primal.joint import JointVarsPrimalComponent\n",
"from miplearn.extractors.fields import H5FieldsExtractor\n",
"from miplearn.solvers.learning import LearningSolver\n",
"from miplearn.components.primal.actions import SetWarmStart\n",
"\n",
"# Configures a primal component that uses a feedforward neural network\n",
@ -206,7 +216,7 @@
"comp = JointVarsPrimalComponent(\n",
" clf=MLPClassifier(),\n",
" extractor=H5FieldsExtractor(\n",
" instance_fields=['static_var_obj_coeffs'],\n",
" instance_fields=[\"static_var_obj_coeffs\"],\n",
" ),\n",
" action=SetWarmStart(),\n",
")\n",
@ -217,31 +227,34 @@
"comp = JointVarsPrimalComponent(\n",
" clf=ClassifierChain(SingleClassFix(LogisticRegression())),\n",
" extractor=H5FieldsExtractor(\n",
" instance_fields=['static_var_obj_coeffs'],\n",
" instance_fields=[\"static_var_obj_coeffs\"],\n",
" ),\n",
" action=SetWarmStart(),\n",
")"
],
"metadata": {
"collapsed": false
}
")\n"
]
},
{
"cell_type": "markdown",
"id": "dddf7be4",
"metadata": {},
"source": [
"## Expert primal component\n",
"\n",
"Before spending time and effort choosing a machine learning strategy and tweaking its parameters, it is usually a good idea to evaluate what would be the performance impact of the model if its predictions were 100% accurate. This is especially important for the prediction of warm starts, since they are not always very beneficial. To simplify this task, MIPLearn provides `ExpertPrimalComponent`, a component which simply loads the optimal solution from the HDF5 file, assuming that it has already been computed, then directly provides it to the solver using one of the available methods. This component is useful in benchmarks, to evaluate how close to the best theoretical performance the machine learning components are.\n",
"\n",
"### Example"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "9e2e81b9",
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"from miplearn.components.primal.expert import ExpertPrimalComponent\n",
@ -250,18 +263,13 @@
"# Configures an expert primal component, which reads a pre-computed\n",
"# optimal solution from the HDF5 file and provides it to the solver\n",
"# as warm start.\n",
"comp = ExpertPrimalComponent(\n",
" action=SetWarmStart()\n",
")"
],
"metadata": {
"collapsed": false
}
"comp = ExpertPrimalComponent(action=SetWarmStart())\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@ -275,7 +283,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.13"
"version": "3.9.12"
}
},
"nbformat": 4,

@ -18,6 +18,9 @@
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"<div class=\"alert alert-warning\">\n",
"Warning\n",
@ -31,10 +34,7 @@
"- To make the instances easier to process, all formulations are written as a minimization problem.\n",
"- Some problem formulations, such as the one for the *traveling salesman problem*, contain an exponential number of constraints, which are enforced through constraint generation. The MPS files for these problems contain only the constraints that were generated during a trial run, not the entire set of constraints. Resolving the MPS file, therefore, may not generate a feasible primal solution for the problem.\n",
"</div>"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
@ -63,6 +63,9 @@
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"\n",
"$$\n",
@ -76,13 +79,13 @@
" & x_{ij} \\in \\{0,1\\} & \\forall i,j=1,\\ldots,n \\\\\n",
"\\end{align*}\n",
"$$"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"### Random instance generator\n",
"\n",
@ -93,19 +96,16 @@
"If `fix_items=True`, the class creates a reference instance, using the method previously described, then generates additional instances by perturbing its item sizes and bin capacity. More specifically, the sizes of the items are set to $s_i \\gamma_i$, where $s_i$ is the size of the $i$-th item in the reference instance and $\\gamma_i$ is sampled from `sizes_jitter`. Similarly, the bin size is set to $B \\beta$, where $B$ is the reference bin size and $\\beta$ is sampled from `capacity_jitter`. The number of items remains the same across all generated instances.\n",
"\n",
"[BinPackGenerator]: ../../api/problems/#miplearn.problems.binpack.BinPackGenerator"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"source": [
"### Example"
],
"metadata": {
"collapsed": false
}
},
"source": [
"### Example"
]
},
{
"cell_type": "code",
@ -130,9 +130,11 @@
"8 [ 8.47 21.9 16.58 15.37 3.76 3.91 1.57 20.57 14.76 18.61] 94.58\n",
"9 [ 8.57 22.77 17.06 16.25 4.14 4. 1.56 22.97 14.09 19.09] 100.79\n",
"\n",
"Restricted license - for non-production use only - expires 2023-10-25\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 20 rows, 110 columns and 210 nonzeros\n",
"Model fingerprint: 0x1ff9913f\n",
"Variable types: 0 continuous, 110 integer (110 binary)\n",
@ -156,7 +158,7 @@
"H 0 0 2.0000000 1.27484 36.3% - 0s\n",
" 0 0 1.27484 0 4 2.00000 1.27484 36.3% - 0s\n",
"\n",
"Explored 1 nodes (38 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Explored 1 nodes (38 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 3: 2 4 5 \n",
@ -164,6 +166,14 @@
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 2.000000000000e+00, best bound 2.000000000000e+00, gap 0.0000%\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/axavier/.conda/envs/miplearn2/lib/python3.9/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n"
]
}
],
"source": [
@ -191,7 +201,7 @@
"\n",
"# Optimize first instance\n",
"model = build_binpack_model(data[0])\n",
"model.optimize()"
"model.optimize()\n"
]
},
{
@ -220,6 +230,9 @@
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"\n",
"$$\n",
@ -234,10 +247,7 @@
" & \\forall j=1,\\ldots,n\n",
"\\end{align*}\n",
"$$"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
@ -289,12 +299,12 @@
},
{
"cell_type": "markdown",
"source": [
"### Example"
],
"metadata": {
"collapsed": false
}
},
"source": [
"### Example"
]
},
{
"cell_type": "code",
@ -317,8 +327,11 @@
"capacities\n",
" [1310. 988. 1004. 1269. 1007.]\n",
"\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 5 rows, 10 columns and 50 nonzeros\n",
"Model fingerprint: 0xaf3ac15e\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n",
@ -344,7 +357,7 @@
"Cutting planes:\n",
" Cover: 1\n",
"\n",
"Explored 1 nodes (4 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Explored 1 nodes (4 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 2: -1279 -804 \n",
@ -388,7 +401,7 @@
"\n",
"# Build model and optimize\n",
"model = build_multiknapsack_model(data[0])\n",
"model.optimize()"
"model.optimize()\n"
]
},
{
@ -453,12 +466,12 @@
},
{
"cell_type": "markdown",
"source": [
"### Example"
],
"metadata": {
"collapsed": false
}
},
"source": [
"### Example"
]
},
{
"cell_type": "code",
@ -485,8 +498,11 @@
"demands = [6.12 1.39 2.92 3.66 4.56 7.85 2. 5.14 5.92 0.46]\n",
"capacities = [151.89 42.63 16.26 237.22 241.41 202.1 76.15 24.42 171.06 110.04]\n",
"\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 21 rows, 110 columns and 220 nonzeros\n",
"Model fingerprint: 0x8d8d9346\n",
"Variable types: 0 continuous, 110 integer (110 binary)\n",
@ -519,7 +535,7 @@
" 0 0 86.06884 0 15 93.92000 86.06884 8.36% - 0s\n",
"* 0 0 0 91.2300000 91.23000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (60 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Explored 1 nodes (70 simplex iterations) in 0.02 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 10: 91.23 93.92 93.98 ... 368.79\n",
@ -561,7 +577,7 @@
"\n",
"# Build and optimize model\n",
"model = build_pmedian_model(data[0])\n",
"model.optimize()"
"model.optimize()\n"
]
},
{
@ -576,14 +592,14 @@
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"### Formulation\n",
"\n",
"Let $U = \\{1,\\ldots,n\\}$ be a given universe set, and let $S=\\{S_1,\\ldots,S_m\\}$ be a collection of sets whose union equal $U$. For each $j \\in \\{1,\\ldots,m\\}$, let $w_j$ be the weight of set $S_j$, and let $x_j$ be a binary decision variable that equals one if set $S_j$ is chosen. The set cover problem is formulated as:"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
@ -650,8 +666,11 @@
"costs [1044.58 850.13 1014.5 944.83 697.9 971.87 213.49 220.98 70.23\n",
" 425.33]\n",
"\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 5 rows, 10 columns and 28 nonzeros\n",
"Model fingerprint: 0xe5c2d4fa\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n",
@ -678,7 +697,7 @@
"source": [
"import numpy as np\n",
"from scipy.stats import uniform, randint\n",
"from miplearn.problems.setcover import SetCoverGenerator, build_setcover_model\n",
"from miplearn.problems.setcover import SetCoverGenerator, build_setcover_model_gurobipy\n",
"\n",
"# Set random seed, to make example reproducible\n",
"np.random.seed(42)\n",
@ -702,8 +721,8 @@
"print()\n",
"\n",
"# Build and optimize model\n",
"model = build_setcover_model(data[0])\n",
"model.optimize()"
"model = build_setcover_model_gurobipy(data[0])\n",
"model.optimize()\n"
]
},
{
@ -718,17 +737,20 @@
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"### Formulation\n",
"\n",
"Let $U=\\{1,\\ldots,n\\}$ be a given universe set, and let $S = \\{S_1, \\ldots, S_m\\}$ be a collection of subsets of $U$. For each subset $j \\in \\{1, \\ldots, m\\}$, let $w_j$ be the weight of $S_j$ and let $x_j$ be a binary decision variable which equals one if set $S_j$ is chosen. The problem is formulated as:"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"$$\n",
"\\begin{align*}\n",
@ -740,13 +762,13 @@
" & x_j \\in \\{0, 1\\} & \\forall j \\in \\{1,\\ldots,m\\}\n",
"\\end{align*}\n",
"$$"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"### Random instance generator\n",
"\n",
@ -756,14 +778,14 @@
"[SetCoverGenerator]: ../../api/problems/#miplearn.problems.setcover.SetCoverGenerator\n",
"\n",
"### Example"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
@ -778,8 +800,11 @@
"costs [1044.58 850.13 1014.5 944.83 697.9 971.87 213.49 220.98 70.23\n",
" 425.33]\n",
"\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 5 rows, 10 columns and 28 nonzeros\n",
"Model fingerprint: 0x4ee91388\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n",
@ -832,11 +857,8 @@
"\n",
"# Build and optimize model\n",
"model = build_setpack_model(data[0])\n",
"model.optimize()"
],
"metadata": {
"collapsed": false
}
"model.optimize()\n"
]
},
{
"cell_type": "markdown",
@ -854,6 +876,9 @@
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"$$\n",
"\\begin{align*}\n",
@ -863,13 +888,13 @@
"\\end{align*}\n",
"$$\n",
"where $\\mathcal{C}$ is the set of cliques in $G$. We recall that a clique is a subset of vertices in which every pair of vertices is adjacent."
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"\n",
"### Random instance generator\n",
@ -881,14 +906,11 @@
"If `fix_graph=True`, then all generated instances have the same random graph. For each instance, the weights are decided by sampling `w`, as described above.\n",
"\n",
"### Example"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "code",
"execution_count": 24,
"execution_count": 6,
"id": "0f996e99-0ec9-472b-be8a-30c9b8556931",
"metadata": {},
"outputs": [
@ -900,8 +922,11 @@
"weights[0] [37.45 95.07 73.2 59.87 15.6 15.6 5.81 86.62 60.11 70.81]\n",
"weights[1] [ 2.06 96.99 83.24 21.23 18.18 18.34 30.42 52.48 43.19 29.12]\n",
"\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 10 rows, 10 columns and 24 nonzeros\n",
"Model fingerprint: 0xf4c21689\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n",
@ -923,7 +948,7 @@
"\n",
" 0 0 infeasible 0 -219.14000 -219.14000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (4 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Explored 1 nodes (4 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 1: -219.14 \n",
@ -938,7 +963,10 @@
"import random\n",
"import numpy as np\n",
"from scipy.stats import uniform, randint\n",
"from miplearn.problems.stab import MaxWeightStableSetGenerator, build_stab_model\n",
"from miplearn.problems.stab import (\n",
" MaxWeightStableSetGenerator,\n",
" build_stab_model_gurobipy,\n",
")\n",
"\n",
"# Set random seed to make example reproducible\n",
"random.seed(42)\n",
@ -960,8 +988,8 @@
"print()\n",
"\n",
"# Load and optimize the first instance\n",
"model = build_stab_model(data[0])\n",
"model.optimize()"
"model = build_stab_model_gurobipy(data[0])\n",
"model.optimize()\n"
]
},
{
@ -976,17 +1004,20 @@
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"### Formulation\n",
"\n",
"Let $G=(V,E)$ be a simple undirected graph. For each edge $e \\in E$, let $d_e$ be its weight (or distance) and let $x_e$ be a binary decision variable which equals one if $e$ is included in the route. The problem is formulated as:"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"$$\n",
"\\begin{align*}\n",
@ -999,13 +1030,13 @@
"\\end{align*}\n",
"$$\n",
"where $\\delta(v)$ denotes the set of edges adjacent to vertex $v$, and $\\delta(S)$ denotes the set of edges that have one extremity in $S$ and one in $V \\setminus S$. Because of its exponential size, we enforce the second set of inequalities as lazy constraints."
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"### Random instance generator\n",
"\n",
@ -1018,23 +1049,23 @@
"If `fix_cities=True`, then the list of cities is kept the same for all generated instances. The $\\gamma$ values, however, and therefore also the distances, are still different. By default, all distances $d_{ij}$ are rounded to the nearest integer. If `round=False` is provided, this rounding will be disabled.\n",
"\n",
"[TravelingSalesmanGenerator]: ../../api/problems/#miplearn.problems.tsp.TravelingSalesmanGenerator"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"source": [
"### Example"
],
"metadata": {
"collapsed": false
}
},
"source": [
"### Example"
]
},
{
"cell_type": "code",
"execution_count": 32,
"execution_count": 7,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
@ -1064,8 +1095,11 @@
" [ 668. 446. 317. 648. 469. 752. 394. 286. 274. 0.]]\n",
"\n",
"Set parameter LazyConstraints to value 1\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 10 rows, 45 columns and 90 nonzeros\n",
"Model fingerprint: 0x719675e5\n",
"Variable types: 0 continuous, 45 integer (45 binary)\n",
@ -1096,7 +1130,7 @@
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 2.921000000000e+03, best bound 2.921000000000e+03, gap 0.0000%\n",
"\n",
"User-callback calls 100, time in user-callback 0.00 sec\n"
"User-callback calls 106, time in user-callback 0.00 sec\n"
]
}
],
@ -1128,11 +1162,8 @@
"\n",
"# Load and optimize the first instance\n",
"model = build_tsp_model(data[0])\n",
"model.optimize()"
],
"metadata": {
"collapsed": false
}
"model.optimize()\n"
]
},
{
"cell_type": "markdown",
@ -1146,6 +1177,9 @@
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"\n",
"<div class=\"alert alert-info\">\n",
@ -1157,13 +1191,13 @@
"### Formulation\n",
"\n",
"Let $T$ be the number of time steps, $G$ be the number of generation units, and let $D_t$ be the power demand (in MW) at time $t$. For each generating unit $g$, let $P^\\max_g$ and $P^\\min_g$ be the maximum and minimum amount of power the unit is able to produce when switched on; let $L_g$ and $l_g$ be the minimum up- and down-time for unit $g$; let $C^\\text{fixed}$ be the cost to keep unit $g$ on for one time step, regardless of its power output level; let $C^\\text{start}$ be the cost to switch unit $g$ on; and let $C^\\text{var}$ be the cost for generator $g$ to produce 1 MW of power. In this formulation, we assume linear production costs. For each generator $g$ and time $t$, let $x_{gt}$ be a binary variable which equals one if unit $g$ is on at time $t$, let $w_{gt}$ be a binary variable which equals one if unit $g$ switches from being off at time $t-1$ to being on at time $t$, and let $p_{gt}$ be a continuous variable which indicates the amount of power generated. The formulation is given by:"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"\n",
"$$\n",
@ -1192,13 +1226,13 @@
" & \\forall g, t.\n",
"\\end{align*}\n",
"$$"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"\n",
"The first set of inequalities enforces minimum up-time constraints: if unit $g$ is down at time $t$, then it cannot start up during the previous $L_g$ time steps. The second set of inequalities enforces minimum down-time constraints, and is symmetrical to the previous one. The third set ensures that if unit $g$ starts up at time $t$, then the start up variable must be one. The fourth set ensures that demand is satisfied at each time period. The fifth and sixth sets enforce bounds to the quantity of power generated by each unit.\n",
@ -1208,13 +1242,13 @@
"\n",
"- *Bendotti, P., Fouilhoux, P. & Rottner, C.* **The min-up/min-down unit commitment polytope.** J Comb Optim 36, 1024-1058 (2018). https://doi.org/10.1007/s10878-018-0273-y\n",
"</div>"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"\n",
"### Random instance generator\n",
@ -1226,23 +1260,23 @@
"After parameters for the units have been generated, the class then generates a periodic demand curve, with a peak every 12 time steps, in the range $(0.4C, 0.8C)$, where $C$ is the sum of all units' maximum power output. Finally, all costs and demand values are perturbed by random scaling factors independently sampled from the distributions `cost_jitter` and `demand_jitter`, respectively.\n",
"\n",
"If `fix_units=True`, then the list of generators (with their respective parameters) is kept the same for all generated instances. If `cost_jitter` and `demand_jitter` are provided, the instances will still have slightly different costs and demands."
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"source": [
"### Example"
],
"metadata": {
"collapsed": false
}
},
"source": [
"### Example"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
@ -1274,8 +1308,11 @@
" 828.28 775.18 834.99 959.76 865.72 1193.52 1058.92 985.19 893.92\n",
" 962.16 781.88 723.15 639.04 602.4 787.02]\n",
"\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 578 rows, 360 columns and 2128 nonzeros\n",
"Model fingerprint: 0x4dc1c661\n",
"Variable types: 120 continuous, 240 integer (240 binary)\n",
@ -1285,22 +1322,22 @@
" Bounds range [1e+00, 1e+00]\n",
" RHS range [1e+00, 1e+03]\n",
"Presolve removed 244 rows and 131 columns\n",
"Presolve time: 0.01s\n",
"Presolve time: 0.02s\n",
"Presolved: 334 rows, 229 columns, 842 nonzeros\n",
"Variable types: 116 continuous, 113 integer (113 binary)\n",
"Found heuristic solution: objective 441426.66550\n",
"Found heuristic solution: objective 440662.46430\n",
"Found heuristic solution: objective 429461.97680\n",
"Found heuristic solution: objective 374043.64040\n",
"\n",
"Root relaxation: objective 3.361348e+05, 139 iterations, 0.00 seconds (0.00 work units)\n",
"Root relaxation: objective 3.361348e+05, 142 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 336134.820 0 18 374043.640 336134.820 10.1% - 0s\n",
"H 0 0 368600.14450 336134.820 8.81% - 0s\n",
"H 0 0 364721.76610 364721.766 0.00% - 0s\n",
" 0 0 - 0 364721.766 364721.766 0.00% - 0s\n",
"H 0 0 364721.76610 336134.820 7.84% - 0s\n",
" 0 0 cutoff 0 364721.766 364721.766 0.00% - 0s\n",
"\n",
"Cutting planes:\n",
" Gomory: 3\n",
@ -1312,10 +1349,10 @@
" RLT: 1\n",
" Relax-and-lift: 7\n",
"\n",
"Explored 1 nodes (232 simplex iterations) in 0.04 seconds (0.02 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Explored 1 nodes (234 simplex iterations) in 0.04 seconds (0.02 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 5: 364722 368600 374044 ... 441427\n",
"Solution count 5: 364722 368600 374044 ... 440662\n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 3.647217661000e+05, best bound 3.647217661000e+05, gap 0.0000%\n"
@ -1363,11 +1400,8 @@
"\n",
"# Load and optimize the first instance\n",
"model = build_uc_model(data[0])\n",
"model.optimize()"
],
"metadata": {
"collapsed": false
}
"model.optimize()\n"
]
},
{
"cell_type": "markdown",
@ -1381,18 +1415,21 @@
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"\n",
"### Formulation\n",
"\n",
"Let $G=(V,E)$ be a simple graph. For each vertex $v \\in V$, let $w_g$ be its weight, and let $x_v$ be a binary decision variable which equals one if $v$ is included in the cover. The mixed-integer linear formulation for the problem is given by:"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
" $$\n",
"\\begin{align*}\n",
@ -1404,13 +1441,13 @@
" & \\forall \\{i,j\\} \\in E.\n",
"\\end{align*}\n",
"$$"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"### Random instance generator\n",
"\n",
@ -1420,10 +1457,7 @@
"[MaxWeightStableSetGenerator]: ../../api/problems/#miplearn.problems.stab.MaxWeightStableSetGenerator\n",
"\n",
"### Example"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "code",
@ -1439,8 +1473,11 @@
"weights[0] [37.45 95.07 73.2 59.87 15.6 15.6 5.81 86.62 60.11 70.81]\n",
"weights[1] [ 2.06 96.99 83.24 21.23 18.18 18.34 30.42 52.48 43.19 29.12]\n",
"\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 15 rows, 10 columns and 30 nonzeros\n",
"Model fingerprint: 0x2d2d1390\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n",
@ -1463,7 +1500,7 @@
" 0 0 infeasible 0 301.00000 301.00000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (8 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 1: 301 \n",
"\n",
@ -1476,7 +1513,10 @@
"import random\n",
"import numpy as np\n",
"from scipy.stats import uniform, randint\n",
"from miplearn.problems.vertexcover import MinWeightVertexCoverGenerator, build_vertexcover_model\n",
"from miplearn.problems.vertexcover import (\n",
" MinWeightVertexCoverGenerator,\n",
" build_vertexcover_model,\n",
")\n",
"\n",
"# Set random seed to make example reproducible\n",
"random.seed(42)\n",
@ -1505,11 +1545,11 @@
{
"cell_type": "code",
"execution_count": null,
"outputs": [],
"source": [],
"metadata": {
"collapsed": false
}
},
"outputs": [],
"source": []
}
],
"metadata": {
@ -1528,7 +1568,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.13"
"version": "3.9.12"
}
},
"nbformat": 4,

@ -14,12 +14,28 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 1,
"id": "92b09b98",
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/axavier/Software/anaconda3/envs/miplearn/lib/python3.8/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Restricted license - for non-production use only - expires 2023-10-25\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"Optimize a model with 10 rows, 45 columns and 90 nonzeros\n",
@ -67,7 +83,7 @@
"Cutting planes:\n",
" Lazy constraints: 3\n",
"\n",
"Explored 1 nodes (15 simplex iterations) in 0.02 seconds (0.00 work units)\n",
"Explored 1 nodes (15 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 1: 2796 \n",
@ -148,7 +164,7 @@
"test_data = all_data[40:]\n",
"\n",
"# Collect training data\n",
"bc = BasicCollector(time_limit_sec=3600)\n",
"bc = BasicCollector()\n",
"bc.collect(train_data, build_tsp_model, n_jobs=4)\n",
"\n",
"# Build learning solver\n",
@ -172,14 +188,11 @@
"\n",
"# Solve a test instance\n",
"solver.optimize(test_data[0], build_tsp_model);"
],
"metadata": {
"collapsed": false
}
]
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 1,
"id": "e27d2cbd-5341-461d-bbc1-8131aee8d949",
"metadata": {},
"outputs": [],
@ -188,7 +201,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},

@ -8,6 +8,15 @@ Unlike pure ML methods, MIPLearn is not only able to find high-quality solutions
Contents
--------
.. toctree::
:maxdepth: 10
:caption: Tutorials
:numbered: 2
tutorials/getting-started-pyomo
tutorials/getting-started-gurobipy
tutorials/getting-started-jump
.. toctree::
:maxdepth: 10
:caption: User Guide
@ -21,7 +30,7 @@ Contents
.. toctree::
:maxdepth: 10
:caption: API Reference
:caption: Python API Reference
:numbered: 2
api/problems

@ -0,0 +1,849 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "6b8983b1",
"metadata": {
"tags": []
},
"source": [
"# Getting started (Gurobipy)\n",
"\n",
"## Introduction\n",
"\n",
"**MIPLearn** is an open source framework that uses machine learning (ML) to accelerate the performance of mixed-integer programming solvers (e.g. Gurobi, CPLEX, XPRESS). In this tutorial, we will:\n",
"\n",
"1. Install the Python/Gurobipy version of MIPLearn\n",
"2. Model a simple optimization problem using Gurobipy\n",
"3. Generate training data and train the ML models\n",
"4. Use the ML models together Gurobi to solve new instances\n",
"\n",
"<div class=\"alert alert-info\">\n",
"Note\n",
" \n",
"The Python/Gurobipy version of MIPLearn is only compatible with the Gurobi Optimizer. For broader solver compatibility, see the Python/Pyomo and Julia/JuMP versions of the package.\n",
"</div>\n",
"\n",
"<div class=\"alert alert-warning\">\n",
"Warning\n",
" \n",
"MIPLearn is still in early development stage. If run into any bugs or issues, please submit a bug report in our GitHub repository. Comments, suggestions and pull requests are also very welcome!\n",
" \n",
"</div>\n"
]
},
{
"cell_type": "markdown",
"id": "02f0a927",
"metadata": {},
"source": [
"## Installation\n",
"\n",
"MIPLearn is available in two versions:\n",
"\n",
"- Python version, compatible with the Pyomo and Gurobipy modeling languages,\n",
"- Julia version, compatible with the JuMP modeling language.\n",
"\n",
"In this tutorial, we will demonstrate how to use and install the Python/Gurobipy version of the package. The first step is to install Python 3.8+ in your computer. See the [official Python website for more instructions](https://www.python.org/downloads/). After Python is installed, we proceed to install MIPLearn using `pip`:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "cd8a69c1",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:18:02.381829278Z",
"start_time": "2023-06-06T20:18:02.381532300Z"
}
},
"outputs": [],
"source": [
"# !pip install MIPLearn==0.3.0"
]
},
{
"cell_type": "markdown",
"id": "e8274543",
"metadata": {},
"source": [
"In addition to MIPLearn itself, we will also install Gurobi 10.0, a state-of-the-art commercial MILP solver. This step also install a demo license for Gurobi, which should able to solve the small optimization problems in this tutorial. A license is required for solving larger-scale problems."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "dcc8756c",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:18:15.537811992Z",
"start_time": "2023-06-06T20:18:13.449177860Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: gurobipy<10.1,>=10 in /home/axavier/Software/anaconda3/envs/miplearn/lib/python3.8/site-packages (10.0.1)\n"
]
}
],
"source": [
"!pip install 'gurobipy>=10,<10.1'"
]
},
{
"cell_type": "markdown",
"id": "a14e4550",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
" \n",
"Note\n",
" \n",
"In the code above, we install specific version of all packages to ensure that this tutorial keeps running in the future, even when newer (and possibly incompatible) versions of the packages are released. This is usually a recommended practice for all Python projects.\n",
" \n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "16b86823",
"metadata": {},
"source": [
"## Modeling a simple optimization problem\n",
"\n",
"To illustrate how can MIPLearn be used, we will model and solve a small optimization problem related to power systems optimization. The problem we discuss below is a simplification of the **unit commitment problem,** a practical optimization problem solved daily by electric grid operators around the world. \n",
"\n",
"Suppose that a utility company needs to decide which electrical generators should be online at each hour of the day, as well as how much power should each generator produce. More specifically, assume that the company owns $n$ generators, denoted by $g_1, \\ldots, g_n$. Each generator can either be online or offline. An online generator $g_i$ can produce between $p^\\text{min}_i$ to $p^\\text{max}_i$ megawatts of power, and it costs the company $c^\\text{fix}_i + c^\\text{var}_i y_i$, where $y_i$ is the amount of power produced. An offline generator produces nothing and costs nothing. The total amount of power to be produced needs to be exactly equal to the total demand $d$ (in megawatts).\n",
"\n",
"This simple problem can be modeled as a *mixed-integer linear optimization* problem as follows. For each generator $g_i$, let $x_i \\in \\{0,1\\}$ be a decision variable indicating whether $g_i$ is online, and let $y_i \\geq 0$ be a decision variable indicating how much power does $g_i$ produce. The problem is then given by:"
]
},
{
"cell_type": "markdown",
"id": "f12c3702",
"metadata": {},
"source": [
"$$\n",
"\\begin{align}\n",
"\\text{minimize } \\quad & \\sum_{i=1}^n \\left( c^\\text{fix}_i x_i + c^\\text{var}_i y_i \\right) \\\\\n",
"\\text{subject to } \\quad & y_i \\leq p^\\text{max}_i x_i & i=1,\\ldots,n \\\\\n",
"& y_i \\geq p^\\text{min}_i x_i & i=1,\\ldots,n \\\\\n",
"& \\sum_{i=1}^n y_i = d \\\\\n",
"& x_i \\in \\{0,1\\} & i=1,\\ldots,n \\\\\n",
"& y_i \\geq 0 & i=1,\\ldots,n\n",
"\\end{align}\n",
"$$"
]
},
{
"cell_type": "markdown",
"id": "be3989ed",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
"\n",
"Note\n",
"\n",
"We use a simplified version of the unit commitment problem in this tutorial just to make it easier to follow. MIPLearn can also handle realistic, large-scale versions of this problem.\n",
"\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "a5fd33f6",
"metadata": {},
"source": [
"Next, let us convert this abstract mathematical formulation into a concrete optimization model, using Python and Pyomo. We start by defining a data class `UnitCommitmentData`, which holds all the input data."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "22a67170-10b4-43d3-8708-014d91141e73",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:18:25.442346786Z",
"start_time": "2023-06-06T20:18:25.329017476Z"
},
"tags": []
},
"outputs": [],
"source": [
"from dataclasses import dataclass\n",
"from typing import List\n",
"\n",
"import numpy as np\n",
"\n",
"\n",
"@dataclass\n",
"class UnitCommitmentData:\n",
" demand: float\n",
" pmin: List[float]\n",
" pmax: List[float]\n",
" cfix: List[float]\n",
" cvar: List[float]"
]
},
{
"cell_type": "markdown",
"id": "29f55efa-0751-465a-9b0a-a821d46a3d40",
"metadata": {},
"source": [
"Next, we write a `build_uc_model` function, which converts the input data into a concrete Pyomo model. The function accepts `UnitCommitmentData`, the data structure we previously defined, or the path to a compressed pickle file containing this data."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "2f67032f-0d74-4317-b45c-19da0ec859e9",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:48:05.953902842Z",
"start_time": "2023-06-06T20:48:05.909747925Z"
}
},
"outputs": [],
"source": [
"import gurobipy as gp\n",
"from gurobipy import GRB, quicksum\n",
"from typing import Union\n",
"from miplearn.io import read_pkl_gz\n",
"from miplearn.solvers.gurobi import GurobiModel\n",
"\n",
"def build_uc_model(data: Union[str, UnitCommitmentData]) -> GurobiModel:\n",
" if isinstance(data, str):\n",
" data = read_pkl_gz(data)\n",
"\n",
" model = gp.Model()\n",
" n = len(data.pmin)\n",
" x = model._x = model.addVars(n, vtype=GRB.BINARY, name=\"x\")\n",
" y = model._y = model.addVars(n, name=\"y\")\n",
" model.setObjective(\n",
" quicksum(\n",
" data.cfix[i] * x[i] + data.cvar[i] * y[i] for i in range(n)\n",
" )\n",
" )\n",
" model.addConstrs(y[i] <= data.pmax[i] * x[i] for i in range(n))\n",
" model.addConstrs(y[i] >= data.pmin[i] * x[i] for i in range(n))\n",
" model.addConstr(quicksum(y[i] for i in range(n)) == data.demand)\n",
" return GurobiModel(model)"
]
},
{
"cell_type": "markdown",
"id": "c22714a3",
"metadata": {},
"source": [
"At this point, we can already use Pyomo 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:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "2a896f47",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:49:14.266758244Z",
"start_time": "2023-06-06T20:49:14.223514806Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Restricted license - for non-production use only - expires 2024-10-28\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 7 rows, 6 columns and 15 nonzeros\n",
"Model fingerprint: 0x58dfdd53\n",
"Variable types: 3 continuous, 3 integer (3 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 7e+01]\n",
" Objective range [2e+00, 7e+02]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [1e+02, 1e+02]\n",
"Presolve removed 2 rows and 1 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 5 rows, 5 columns, 13 nonzeros\n",
"Variable types: 0 continuous, 5 integer (3 binary)\n",
"Found heuristic solution: objective 1400.0000000\n",
"\n",
"Root relaxation: objective 1.035000e+03, 3 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 1035.00000 0 1 1400.00000 1035.00000 26.1% - 0s\n",
" 0 0 1105.71429 0 1 1400.00000 1105.71429 21.0% - 0s\n",
"* 0 0 0 1320.0000000 1320.00000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (5 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 2: 1320 1400 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 1.320000000000e+03, best bound 1.320000000000e+03, gap 0.0000%\n",
"obj = 1320.0\n",
"x = [-0.0, 1.0, 1.0]\n",
"y = [0.0, 60.0, 40.0]\n"
]
}
],
"source": [
"model = build_uc_model(\n",
" UnitCommitmentData(\n",
" demand=100.0,\n",
" pmin=[10, 20, 30],\n",
" pmax=[50, 60, 70],\n",
" cfix=[700, 600, 500],\n",
" cvar=[1.5, 2.0, 2.5],\n",
" )\n",
")\n",
"\n",
"model.optimize()\n",
"print(\"obj =\", model.inner.objVal)\n",
"print(\"x =\", [model.inner._x[i].x for i in range(3)])\n",
"print(\"y =\", [model.inner._y[i].x for i in range(3)])"
]
},
{
"cell_type": "markdown",
"id": "41b03bbc",
"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."
]
},
{
"cell_type": "markdown",
"id": "01f576e1-1790-425e-9e5c-9fa07b6f4c26",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
" \n",
"Note\n",
"\n",
"- In the example above, `GurobiModel` is just a thin wrapper around a standard Gurobi model. This wrapper allows MIPLearn to be solver- and modeling-language-agnostic. The wrapper provides only a few basic methods, such as `optimize`. For more control, and to query the solution, the original Gurobi model can be accessed through `model.inner`, as illustrated above.\n",
"- To ensure training data consistency, MIPLearn requires all decision variables to have names.\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "cf60c1dd",
"metadata": {},
"source": [
"## Generating training data\n",
"\n",
"Although Gurobi could solve the small example above in a fraction of a second, it gets slower for larger and more complex versions of the problem. If this is a problem that needs to be solved frequently, as it is often the case in practice, it could make sense to spend some time upfront generating a **trained** solver, which can optimize new instances (similar to the ones it was trained on) faster.\n",
"\n",
"In the following, we will use MIPLearn to train machine learning models that is able to predict the optimal solution for instances that follow a given probability distribution, then it will provide this predicted solution to Gurobi as a warm start. Before we can train the model, we need to collect training data by solving a large number of instances. In real-world situations, we may construct these training instances based on historical data. In this tutorial, we will construct them using a random instance generator:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "5eb09fab",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:49:22.758192368Z",
"start_time": "2023-06-06T20:49:22.724784572Z"
}
},
"outputs": [],
"source": [
"from scipy.stats import uniform\n",
"from typing import List\n",
"import random\n",
"\n",
"\n",
"def random_uc_data(samples: int, n: int, seed: int = 42) -> List[UnitCommitmentData]:\n",
" random.seed(seed)\n",
" np.random.seed(seed)\n",
" pmin = uniform(loc=100_000.0, scale=400_000.0).rvs(n)\n",
" pmax = pmin * uniform(loc=2.0, scale=2.5).rvs(n)\n",
" cfix = pmin * uniform(loc=100.0, scale=25.0).rvs(n)\n",
" cvar = uniform(loc=1.25, scale=0.25).rvs(n)\n",
" return [\n",
" UnitCommitmentData(\n",
" demand=pmax.sum() * uniform(loc=0.5, scale=0.25).rvs(),\n",
" pmin=pmin,\n",
" pmax=pmax,\n",
" cfix=cfix,\n",
" cvar=cvar,\n",
" )\n",
" for _ in range(samples)\n",
" ]"
]
},
{
"cell_type": "markdown",
"id": "3a03a7ac",
"metadata": {},
"source": [
"In this example, for simplicity, only the demands change from one instance to the next. We could also have randomized the costs, production limits or even the number of units. 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",
"\n",
"Now we generate 500 instances of this problem, each one with 50 generators, and we use 450 of these instances for training. After generating the instances, we write them to individual files. MIPLearn uses files during the training process because, for large-scale optimization problems, it is often impractical to hold in memory the entire training data, as well as the concrete Pyomo models. Files also make it much easier to solve multiple instances simultaneously, potentially on multiple machines. The code below generates the files `uc/train/00000.pkl.gz`, `uc/train/00001.pkl.gz`, etc., which contain the input data in compressed (gzipped) pickle format."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "6156752c",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:49:24.811192929Z",
"start_time": "2023-06-06T20:49:24.575639142Z"
}
},
"outputs": [],
"source": [
"from miplearn.io import write_pkl_gz\n",
"\n",
"data = random_uc_data(samples=500, n=500)\n",
"train_data = write_pkl_gz(data[0:450], \"uc/train\")\n",
"test_data = write_pkl_gz(data[450:500], \"uc/test\")"
]
},
{
"cell_type": "markdown",
"id": "b17af877",
"metadata": {},
"source": [
"Finally, we use `BasicCollector` to collect the optimal solutions and other useful training data for all training instances. The data is stored in HDF5 files `uc/train/00000.h5`, `uc/train/00001.h5`, etc. The optimization models are also exported to compressed MPS files `uc/train/00000.mps.gz`, `uc/train/00001.mps.gz`, etc."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "7623f002",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:49:34.936729253Z",
"start_time": "2023-06-06T20:49:25.936126612Z"
}
},
"outputs": [],
"source": [
"from miplearn.collectors.basic import BasicCollector\n",
"\n",
"bc = BasicCollector()\n",
"bc.collect(train_data, build_uc_model, n_jobs=4)"
]
},
{
"cell_type": "markdown",
"id": "c42b1be1-9723-4827-82d8-974afa51ef9f",
"metadata": {},
"source": [
"## Training and solving test instances"
]
},
{
"cell_type": "markdown",
"id": "a33c6aa4-f0b8-4ccb-9935-01f7d7de2a1c",
"metadata": {},
"source": [
"With training data in hand, we can now design and train a machine learning model to accelerate solver performance. In this tutorial, for illustration purposes, we will use ML to generate a good warm start using $k$-nearest neighbors. More specifically, the strategy is to:\n",
"\n",
"1. Memorize the optimal solutions of all training instances;\n",
"2. Given a test instance, find the 25 most similar training instances, based on constraint right-hand sides;\n",
"3. Merge their optimal solutions into a single partial solution; specifically, only assign values to the binary variables that agree unanimously.\n",
"4. Provide this partial solution to the solver as a warm start.\n",
"\n",
"This simple strategy can be implemented as shown below, using `MemorizingPrimalComponent`. For more advanced strategies, and for the usage of more advanced classifiers, see the user guide."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "435f7bf8-4b09-4889-b1ec-b7b56e7d8ed2",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:49:38.997939600Z",
"start_time": "2023-06-06T20:49:38.968261432Z"
}
},
"outputs": [],
"source": [
"from sklearn.neighbors import KNeighborsClassifier\n",
"from miplearn.components.primal.actions import SetWarmStart\n",
"from miplearn.components.primal.mem import (\n",
" MemorizingPrimalComponent,\n",
" MergeTopSolutions,\n",
")\n",
"from miplearn.extractors.fields import H5FieldsExtractor\n",
"\n",
"comp = MemorizingPrimalComponent(\n",
" clf=KNeighborsClassifier(n_neighbors=25),\n",
" extractor=H5FieldsExtractor(\n",
" instance_fields=[\"static_constr_rhs\"],\n",
" ),\n",
" constructor=MergeTopSolutions(25, [0.0, 1.0]),\n",
" action=SetWarmStart(),\n",
")"
]
},
{
"cell_type": "markdown",
"id": "9536e7e4-0b0d-49b0-bebd-4a848f839e94",
"metadata": {},
"source": [
"Having defined the ML strategy, we next construct `LearningSolver`, train the ML component and optimize one of the test instances."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "9d13dd50-3dcf-4673-a757-6f44dcc0dedf",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:49:42.072345411Z",
"start_time": "2023-06-06T20:49:41.294040974Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0xa8b70287\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
" 0 6.6166537e+09 5.648803e+04 0.000000e+00 0s\n",
" 1 8.2906219e+09 0.000000e+00 0.000000e+00 0s\n",
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.290621916e+09\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x4ccd7ae3\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"\n",
"User MIP start produced solution with objective 8.30129e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29184e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29146e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29146e+09 (0.01s)\n",
"Loaded user MIP start with objective 8.29146e+09\n",
"\n",
"Presolve time: 0.00s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
"Root relaxation: objective 8.290622e+09, 512 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 8.2906e+09 0 1 8.2915e+09 8.2906e+09 0.01% - 0s\n",
"\n",
"Cutting planes:\n",
" Cover: 1\n",
" Flow cover: 2\n",
"\n",
"Explored 1 nodes (512 simplex iterations) in 0.07 seconds (0.01 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 3: 8.29146e+09 8.29184e+09 8.30129e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 8.291459497797e+09, best bound 8.290645029670e+09, gap 0.0098%\n"
]
}
],
"source": [
"from miplearn.solvers.learning import LearningSolver\n",
"\n",
"solver_ml = LearningSolver(components=[comp])\n",
"solver_ml.fit(train_data)\n",
"solver_ml.optimize(test_data[0], build_uc_model);"
]
},
{
"cell_type": "markdown",
"id": "61da6dad-7f56-4edb-aa26-c00eb5f946c0",
"metadata": {},
"source": [
"By examining the solve log above, specifically the line `Loaded user MIP start with objective...`, we can see that MIPLearn was able to construct an initial solution which turned out to be very close to the optimal solution to the problem. Now let us repeat the code above, but a solver which does not apply any ML strategies. Note that our previously-defined component is not provided."
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "2ff391ed-e855-4228-aa09-a7641d8c2893",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:49:44.012782276Z",
"start_time": "2023-06-06T20:49:43.813974362Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0xa8b70287\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
" 0 6.6166537e+09 5.648803e+04 0.000000e+00 0s\n",
" 1 8.2906219e+09 0.000000e+00 0.000000e+00 0s\n",
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.290621916e+09\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x4cbbf7c7\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve time: 0.00s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Found heuristic solution: objective 9.757128e+09\n",
"\n",
"Root relaxation: objective 8.290622e+09, 512 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 8.2906e+09 0 1 9.7571e+09 8.2906e+09 15.0% - 0s\n",
"H 0 0 8.298273e+09 8.2906e+09 0.09% - 0s\n",
" 0 0 8.2907e+09 0 4 8.2983e+09 8.2907e+09 0.09% - 0s\n",
" 0 0 8.2907e+09 0 1 8.2983e+09 8.2907e+09 0.09% - 0s\n",
" 0 0 8.2907e+09 0 4 8.2983e+09 8.2907e+09 0.09% - 0s\n",
"H 0 0 8.293980e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2907e+09 0 5 8.2940e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2907e+09 0 1 8.2940e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2907e+09 0 2 8.2940e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2908e+09 0 1 8.2940e+09 8.2908e+09 0.04% - 0s\n",
" 0 0 8.2908e+09 0 4 8.2940e+09 8.2908e+09 0.04% - 0s\n",
" 0 0 8.2908e+09 0 4 8.2940e+09 8.2908e+09 0.04% - 0s\n",
"H 0 0 8.291465e+09 8.2908e+09 0.01% - 0s\n",
"\n",
"Cutting planes:\n",
" Gomory: 2\n",
" MIR: 1\n",
"\n",
"Explored 1 nodes (1031 simplex iterations) in 0.07 seconds (0.03 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 4: 8.29147e+09 8.29398e+09 8.29827e+09 9.75713e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 8.291465302389e+09, best bound 8.290781665333e+09, gap 0.0082%\n"
]
}
],
"source": [
"solver_baseline = LearningSolver(components=[])\n",
"solver_baseline.fit(train_data)\n",
"solver_baseline.optimize(test_data[0], build_uc_model);"
]
},
{
"cell_type": "markdown",
"id": "b6d37b88-9fcc-43ee-ac1e-2a7b1e51a266",
"metadata": {},
"source": [
"In the log above, the `MIP start` line is missing, and Gurobi had to start with a significantly inferior initial solution. The solver was still able to find the optimal solution at the end, but it required using its own internal heuristic procedures. In this example, because we solve very small optimization problems, there was almost no difference in terms of running time, but the difference can be significant for larger problems."
]
},
{
"cell_type": "markdown",
"id": "eec97f06",
"metadata": {
"tags": []
},
"source": [
"## Accessing the solution\n",
"\n",
"In the example above, we used `LearningSolver.solve` together with data files to solve both the training and the test instances. The optimal solutions were saved to HDF5 files in the train/test folders, and could be retrieved by reading theses files, but that is not very convenient. In the following example, we show how to build and solve a Pyomo model entirely in-memory, using our trained solver."
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "67a6cd18",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:50:12.869892930Z",
"start_time": "2023-06-06T20:50:12.509410473Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x19042f12\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
" 0 6.5917580e+09 5.627453e+04 0.000000e+00 0s\n",
" 1 8.2535968e+09 0.000000e+00 0.000000e+00 0s\n",
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.253596777e+09\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x8ee64638\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"\n",
"User MIP start produced solution with objective 8.25814e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25512e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.04s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.04s)\n",
"Loaded user MIP start with objective 8.25459e+09\n",
"\n",
"Presolve time: 0.01s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
"Root relaxation: objective 8.253597e+09, 512 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 8.2536e+09 0 1 8.2546e+09 8.2536e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 3 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 1 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 4 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 4 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2538e+09 0 4 8.2546e+09 8.2538e+09 0.01% - 0s\n",
" 0 0 8.2538e+09 0 5 8.2546e+09 8.2538e+09 0.01% - 0s\n",
" 0 0 8.2538e+09 0 6 8.2546e+09 8.2538e+09 0.01% - 0s\n",
"\n",
"Cutting planes:\n",
" Cover: 1\n",
" MIR: 2\n",
" StrongCG: 1\n",
" Flow cover: 1\n",
"\n",
"Explored 1 nodes (575 simplex iterations) in 0.12 seconds (0.01 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 3: 8.25459e+09 8.25512e+09 8.25814e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 8.254590409970e+09, best bound 8.253768093811e+09, gap 0.0100%\n",
"obj = 8254590409.969726\n",
"x = [1.0, 1.0, 0.0]\n",
"y = [935662.0949263407, 1604270.0218116897, 0.0]\n"
]
}
],
"source": [
"data = random_uc_data(samples=1, n=500)[0]\n",
"model = build_uc_model(data)\n",
"solver_ml.optimize(model)\n",
"print(\"obj =\", model.inner.objVal)\n",
"print(\"x =\", [model.inner._x[i].x for i in range(3)])\n",
"print(\"y =\", [model.inner._y[i].x for i in range(3)])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5593d23a-83bd-4e16-8253-6300f5e3f63b",
"metadata": {},
"outputs": [],
"source": []
}
],
"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.9.16"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

@ -0,0 +1,680 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "6b8983b1",
"metadata": {
"tags": []
},
"source": [
"# Getting started (JuMP)\n",
"\n",
"## Introduction\n",
"\n",
"**MIPLearn** is an open source framework that uses machine learning (ML) to accelerate the performance of mixed-integer programming solvers (e.g. Gurobi, CPLEX, XPRESS). In this tutorial, we will:\n",
"\n",
"1. Install the Julia/JuMP version of MIPLearn\n",
"2. Model a simple optimization problem using JuMP\n",
"3. Generate training data and train the ML models\n",
"4. Use the ML models together Gurobi to solve new instances\n",
"\n",
"<div class=\"alert alert-warning\">\n",
"Warning\n",
" \n",
"MIPLearn is still in early development stage. If run into any bugs or issues, please submit a bug report in our GitHub repository. Comments, suggestions and pull requests are also very welcome!\n",
" \n",
"</div>\n"
]
},
{
"cell_type": "markdown",
"id": "02f0a927",
"metadata": {},
"source": [
"## Installation\n",
"\n",
"MIPLearn is available in two versions:\n",
"\n",
"- Python version, compatible with the Pyomo and Gurobipy modeling languages,\n",
"- Julia version, compatible with the JuMP modeling language.\n",
"\n",
"In this tutorial, we will demonstrate how to use and install the Python/Pyomo version of the package. The first step is to install Julia in your machine. See the [official Julia website for more instructions](https://julialang.org/downloads/). After Julia is installed, launch the Julia REPL, type `]` to enter package mode, then install MIPLearn:\n",
"\n",
"```\n",
"pkg> add MIPLearn@0.3\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "e8274543",
"metadata": {},
"source": [
"In addition to MIPLearn itself, we will also install:\n",
"\n",
"- the JuMP modeling language\n",
"- Gurobi, a state-of-the-art commercial MILP solver\n",
"- Distributions, to generate random data\n",
"- PyCall, to access ML model from Scikit-Learn\n",
"- Suppressor, to make the output cleaner\n",
"\n",
"```\n",
"pkg> add JuMP@1, Gurobi@1, Distributions@0.25, PyCall@1, Suppressor@0.2\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "a14e4550",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
" \n",
"Note\n",
"\n",
"- If you do not have a Gurobi license available, you can also follow the tutorial by installing an open-source solver, such as `HiGHS`, and replacing `Gurobi.Optimizer` by `HiGHS.Optimizer` in all the code examples.\n",
"- In the code above, we install specific version of all packages to ensure that this tutorial keeps running in the future, even when newer (and possibly incompatible) versions of the packages are released. This is usually a recommended practice for all Julia projects.\n",
" \n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "16b86823",
"metadata": {},
"source": [
"## Modeling a simple optimization problem\n",
"\n",
"To illustrate how can MIPLearn be used, we will model and solve a small optimization problem related to power systems optimization. The problem we discuss below is a simplification of the **unit commitment problem,** a practical optimization problem solved daily by electric grid operators around the world. \n",
"\n",
"Suppose that a utility company needs to decide which electrical generators should be online at each hour of the day, as well as how much power should each generator produce. More specifically, assume that the company owns $n$ generators, denoted by $g_1, \\ldots, g_n$. Each generator can either be online or offline. An online generator $g_i$ can produce between $p^\\text{min}_i$ to $p^\\text{max}_i$ megawatts of power, and it costs the company $c^\\text{fix}_i + c^\\text{var}_i y_i$, where $y_i$ is the amount of power produced. An offline generator produces nothing and costs nothing. The total amount of power to be produced needs to be exactly equal to the total demand $d$ (in megawatts).\n",
"\n",
"This simple problem can be modeled as a *mixed-integer linear optimization* problem as follows. For each generator $g_i$, let $x_i \\in \\{0,1\\}$ be a decision variable indicating whether $g_i$ is online, and let $y_i \\geq 0$ be a decision variable indicating how much power does $g_i$ produce. The problem is then given by:"
]
},
{
"cell_type": "markdown",
"id": "f12c3702",
"metadata": {},
"source": [
"$$\n",
"\\begin{align}\n",
"\\text{minimize } \\quad & \\sum_{i=1}^n \\left( c^\\text{fix}_i x_i + c^\\text{var}_i y_i \\right) \\\\\n",
"\\text{subject to } \\quad & y_i \\leq p^\\text{max}_i x_i & i=1,\\ldots,n \\\\\n",
"& y_i \\geq p^\\text{min}_i x_i & i=1,\\ldots,n \\\\\n",
"& \\sum_{i=1}^n y_i = d \\\\\n",
"& x_i \\in \\{0,1\\} & i=1,\\ldots,n \\\\\n",
"& y_i \\geq 0 & i=1,\\ldots,n\n",
"\\end{align}\n",
"$$"
]
},
{
"cell_type": "markdown",
"id": "be3989ed",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
"\n",
"Note\n",
"\n",
"We use a simplified version of the unit commitment problem in this tutorial just to make it easier to follow. MIPLearn can also handle realistic, large-scale versions of this problem.\n",
"\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "a5fd33f6",
"metadata": {},
"source": [
"Next, let us convert this abstract mathematical formulation into a concrete optimization model, using Julia and JuMP. We start by defining a data class `UnitCommitmentData`, which holds all the input data."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "c62ebff1-db40-45a1-9997-d121837f067b",
"metadata": {},
"outputs": [],
"source": [
"struct UnitCommitmentData\n",
" demand::Float64\n",
" pmin::Vector{Float64}\n",
" pmax::Vector{Float64}\n",
" cfix::Vector{Float64}\n",
" cvar::Vector{Float64}\n",
"end;"
]
},
{
"cell_type": "markdown",
"id": "29f55efa-0751-465a-9b0a-a821d46a3d40",
"metadata": {},
"source": [
"Next, we write a `build_uc_model` function, which converts the input data into a concrete JuMP model. The function accepts `UnitCommitmentData`, the data structure we previously defined, or the path to a JLD2 file containing this data."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "79ef7775-18ca-4dfa-b438-49860f762ad0",
"metadata": {},
"outputs": [],
"source": [
"using MIPLearn\n",
"using JuMP\n",
"using Gurobi\n",
"\n",
"function build_uc_model(data)\n",
" if data isa String\n",
" data = read_jld2(data)\n",
" end\n",
" model = Model(Gurobi.Optimizer)\n",
" G = 1:length(data.pmin)\n",
" @variable(model, x[G], Bin)\n",
" @variable(model, y[G] >= 0)\n",
" @objective(model, Min, sum(data.cfix[g] * x[g] + data.cvar[g] * y[g] for g in G))\n",
" @constraint(model, eq_max_power[g in G], y[g] <= data.pmax[g] * x[g])\n",
" @constraint(model, eq_min_power[g in G], y[g] >= data.pmin[g] * x[g])\n",
" @constraint(model, eq_demand, sum(y[g] for g in G) == data.demand)\n",
" return JumpModel(model)\n",
"end;"
]
},
{
"cell_type": "markdown",
"id": "c22714a3",
"metadata": {},
"source": [
"At this point, we can already use Gurobi to find optimal solutions to any instance of this problem. To illustrate this, let us solve a small instance with three generators:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "dd828d68-fd43-4d2a-a058-3e2628d99d9e",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:01:10.993801745Z",
"start_time": "2023-06-06T20:01:10.887580927Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 7 rows, 6 columns and 15 nonzeros\n",
"Model fingerprint: 0x55e33a07\n",
"Variable types: 3 continuous, 3 integer (3 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 7e+01]\n",
" Objective range [2e+00, 7e+02]\n",
" Bounds range [0e+00, 0e+00]\n",
" RHS range [1e+02, 1e+02]\n",
"Presolve removed 2 rows and 1 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 5 rows, 5 columns, 13 nonzeros\n",
"Variable types: 0 continuous, 5 integer (3 binary)\n",
"Found heuristic solution: objective 1400.0000000\n",
"\n",
"Root relaxation: objective 1.035000e+03, 3 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 1035.00000 0 1 1400.00000 1035.00000 26.1% - 0s\n",
" 0 0 1105.71429 0 1 1400.00000 1105.71429 21.0% - 0s\n",
"* 0 0 0 1320.0000000 1320.00000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (5 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 2: 1320 1400 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 1.320000000000e+03, best bound 1.320000000000e+03, gap 0.0000%\n",
"\n",
"User-callback calls 371, time in user-callback 0.00 sec\n",
"objective_value(model.inner) = 1320.0\n",
"Vector(value.(model.inner[:x])) = [-0.0, 1.0, 1.0]\n",
"Vector(value.(model.inner[:y])) = [0.0, 60.0, 40.0]\n"
]
}
],
"source": [
"model = build_uc_model(\n",
" UnitCommitmentData(\n",
" 100.0, # demand\n",
" [10, 20, 30], # pmin\n",
" [50, 60, 70], # pmax\n",
" [700, 600, 500], # cfix\n",
" [1.5, 2.0, 2.5], # cvar\n",
" )\n",
")\n",
"model.optimize()\n",
"@show objective_value(model.inner)\n",
"@show Vector(value.(model.inner[:x]))\n",
"@show Vector(value.(model.inner[:y]));"
]
},
{
"cell_type": "markdown",
"id": "41b03bbc",
"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."
]
},
{
"cell_type": "markdown",
"id": "01f576e1-1790-425e-9e5c-9fa07b6f4c26",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
" \n",
"Notes\n",
" \n",
"- In the example above, `JumpModel` is just a thin wrapper around a standard JuMP model. This wrapper allows MIPLearn to be solver- and modeling-language-agnostic. The wrapper provides only a few basic methods, such as `optimize`. For more control, and to query the solution, the original JuMP model can be accessed through `model.inner`, as illustrated above.\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "cf60c1dd",
"metadata": {},
"source": [
"## Generating training data\n",
"\n",
"Although Gurobi could solve the small example above in a fraction of a second, it gets slower for larger and more complex versions of the problem. If this is a problem that needs to be solved frequently, as it is often the case in practice, it could make sense to spend some time upfront generating a **trained** solver, which can optimize new instances (similar to the ones it was trained on) faster.\n",
"\n",
"In the following, we will use MIPLearn to train machine learning models that is able to predict the optimal solution for instances that follow a given probability distribution, then it will provide this predicted solution to Gurobi as a warm start. Before we can train the model, we need to collect training data by solving a large number of instances. In real-world situations, we may construct these training instances based on historical data. In this tutorial, we will construct them using a random instance generator:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "1326efd7-3869-4137-ab6b-df9cb609a7e0",
"metadata": {},
"outputs": [],
"source": [
"using Distributions\n",
"using Random\n",
"\n",
"function random_uc_data(; samples::Int, n::Int, seed::Int=42)::Vector\n",
" Random.seed!(seed)\n",
" pmin = rand(Uniform(100_000, 500_000), n)\n",
" pmax = pmin .* rand(Uniform(2, 2.5), n)\n",
" cfix = pmin .* rand(Uniform(100, 125), n)\n",
" cvar = rand(Uniform(1.25, 1.50), n)\n",
" return [\n",
" UnitCommitmentData(\n",
" sum(pmax) * rand(Uniform(0.5, 0.75)),\n",
" pmin,\n",
" pmax,\n",
" cfix,\n",
" cvar,\n",
" )\n",
" for _ in 1:samples\n",
" ]\n",
"end;"
]
},
{
"cell_type": "markdown",
"id": "3a03a7ac",
"metadata": {},
"source": [
"In this example, for simplicity, only the demands change from one instance to the next. We could also have randomized the costs, production limits or even the number of units. 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",
"\n",
"Now we generate 500 instances of this problem, each one with 50 generators, and we use 450 of these instances for training. After generating the instances, we write them to individual files. MIPLearn uses files during the training process because, for large-scale optimization problems, it is often impractical to hold in memory the entire training data, as well as the concrete Pyomo models. Files also make it much easier to solve multiple instances simultaneously, potentially on multiple machines. The code below generates the files `uc/train/00001.jld2`, `uc/train/00002.jld2`, etc., which contain the input data in JLD2 format."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "6156752c",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:03:04.782830561Z",
"start_time": "2023-06-06T20:03:04.530421396Z"
}
},
"outputs": [],
"source": [
"data = random_uc_data(samples=500, n=500)\n",
"train_data = write_jld2(data[1:450], \"uc/train\")\n",
"test_data = write_jld2(data[451:500], \"uc/test\");"
]
},
{
"cell_type": "markdown",
"id": "b17af877",
"metadata": {},
"source": [
"Finally, we use `BasicCollector` to collect the optimal solutions and other useful training data for all training instances. The data is stored in HDF5 files `uc/train/00001.h5`, `uc/train/00002.h5`, etc. The optimization models are also exported to compressed MPS files `uc/train/00001.mps.gz`, `uc/train/00002.mps.gz`, etc."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "7623f002",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:03:35.571497019Z",
"start_time": "2023-06-06T20:03:25.804104036Z"
}
},
"outputs": [],
"source": [
"using Suppressor\n",
"@suppress_out begin\n",
" bc = BasicCollector()\n",
" bc.collect(train_data, build_uc_model)\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "c42b1be1-9723-4827-82d8-974afa51ef9f",
"metadata": {},
"source": [
"## Training and solving test instances"
]
},
{
"cell_type": "markdown",
"id": "a33c6aa4-f0b8-4ccb-9935-01f7d7de2a1c",
"metadata": {},
"source": [
"With training data in hand, we can now design and train a machine learning model to accelerate solver performance. In this tutorial, for illustration purposes, we will use ML to generate a good warm start using $k$-nearest neighbors. More specifically, the strategy is to:\n",
"\n",
"1. Memorize the optimal solutions of all training instances;\n",
"2. Given a test instance, find the 25 most similar training instances, based on constraint right-hand sides;\n",
"3. Merge their optimal solutions into a single partial solution; specifically, only assign values to the binary variables that agree unanimously.\n",
"4. Provide this partial solution to the solver as a warm start.\n",
"\n",
"This simple strategy can be implemented as shown below, using `MemorizingPrimalComponent`. For more advanced strategies, and for the usage of more advanced classifiers, see the user guide."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "435f7bf8-4b09-4889-b1ec-b7b56e7d8ed2",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:05:20.497772794Z",
"start_time": "2023-06-06T20:05:20.484821405Z"
}
},
"outputs": [],
"source": [
"# Load kNN classifier from Scikit-Learn\n",
"using PyCall\n",
"KNeighborsClassifier = pyimport(\"sklearn.neighbors\").KNeighborsClassifier\n",
"\n",
"# Build the MIPLearn component\n",
"comp = MemorizingPrimalComponent(\n",
" clf=KNeighborsClassifier(n_neighbors=25),\n",
" extractor=H5FieldsExtractor(\n",
" instance_fields=[\"static_constr_rhs\"],\n",
" ),\n",
" constructor=MergeTopSolutions(25, [0.0, 1.0]),\n",
" action=SetWarmStart(),\n",
");"
]
},
{
"cell_type": "markdown",
"id": "9536e7e4-0b0d-49b0-bebd-4a848f839e94",
"metadata": {},
"source": [
"Having defined the ML strategy, we next construct `LearningSolver`, train the ML component and optimize one of the test instances."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "9d13dd50-3dcf-4673-a757-6f44dcc0dedf",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:05:22.672002339Z",
"start_time": "2023-06-06T20:05:21.447466634Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0xd2378195\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 1e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [0e+00, 0e+00]\n",
" RHS range [2e+08, 2e+08]\n",
"\n",
"User MIP start produced solution with objective 1.02165e+10 (0.00s)\n",
"Loaded user MIP start with objective 1.02165e+10\n",
"\n",
"Presolve time: 0.00s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
"Root relaxation: objective 1.021568e+10, 510 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 1.0216e+10 0 1 1.0217e+10 1.0216e+10 0.01% - 0s\n",
"\n",
"Explored 1 nodes (510 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 1: 1.02165e+10 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 1.021651058978e+10, best bound 1.021567971257e+10, gap 0.0081%\n",
"\n",
"User-callback calls 169, time in user-callback 0.00 sec\n"
]
}
],
"source": [
"solver_ml = LearningSolver(components=[comp])\n",
"solver_ml.fit(train_data)\n",
"solver_ml.optimize(test_data[1], build_uc_model);"
]
},
{
"cell_type": "markdown",
"id": "61da6dad-7f56-4edb-aa26-c00eb5f946c0",
"metadata": {},
"source": [
"By examining the solve log above, specifically the line `Loaded user MIP start with objective...`, we can see that MIPLearn was able to construct an initial solution which turned out to be very close to the optimal solution to the problem. Now let us repeat the code above, but a solver which does not apply any ML strategies. Note that our previously-defined component is not provided."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "2ff391ed-e855-4228-aa09-a7641d8c2893",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:05:46.969575966Z",
"start_time": "2023-06-06T20:05:46.420803286Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0xb45c0594\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 1e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [0e+00, 0e+00]\n",
" RHS range [2e+08, 2e+08]\n",
"Presolve time: 0.00s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Found heuristic solution: objective 1.071463e+10\n",
"\n",
"Root relaxation: objective 1.021568e+10, 510 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 1.0216e+10 0 1 1.0715e+10 1.0216e+10 4.66% - 0s\n",
"H 0 0 1.025162e+10 1.0216e+10 0.35% - 0s\n",
" 0 0 1.0216e+10 0 1 1.0252e+10 1.0216e+10 0.35% - 0s\n",
"H 0 0 1.023090e+10 1.0216e+10 0.15% - 0s\n",
"H 0 0 1.022335e+10 1.0216e+10 0.07% - 0s\n",
"H 0 0 1.022281e+10 1.0216e+10 0.07% - 0s\n",
"H 0 0 1.021753e+10 1.0216e+10 0.02% - 0s\n",
"H 0 0 1.021752e+10 1.0216e+10 0.02% - 0s\n",
" 0 0 1.0216e+10 0 3 1.0218e+10 1.0216e+10 0.02% - 0s\n",
" 0 0 1.0216e+10 0 1 1.0218e+10 1.0216e+10 0.02% - 0s\n",
"H 0 0 1.021651e+10 1.0216e+10 0.01% - 0s\n",
"\n",
"Explored 1 nodes (764 simplex iterations) in 0.03 seconds (0.02 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 7: 1.02165e+10 1.02175e+10 1.02228e+10 ... 1.07146e+10\n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 1.021651058978e+10, best bound 1.021573363741e+10, gap 0.0076%\n",
"\n",
"User-callback calls 204, time in user-callback 0.00 sec\n"
]
}
],
"source": [
"solver_baseline = LearningSolver(components=[])\n",
"solver_baseline.fit(train_data)\n",
"solver_baseline.optimize(test_data[1], build_uc_model);"
]
},
{
"cell_type": "markdown",
"id": "b6d37b88-9fcc-43ee-ac1e-2a7b1e51a266",
"metadata": {},
"source": [
"In the log above, the `MIP start` line is missing, and Gurobi had to start with a significantly inferior initial solution. The solver was still able to find the optimal solution at the end, but it required using its own internal heuristic procedures. In this example, because we solve very small optimization problems, there was almost no difference in terms of running time, but the difference can be significant for larger problems."
]
},
{
"cell_type": "markdown",
"id": "eec97f06",
"metadata": {
"tags": []
},
"source": [
"## Accessing the solution\n",
"\n",
"In the example above, we used `LearningSolver.solve` together with data files to solve both the training and the test instances. The optimal solutions were saved to HDF5 files in the train/test folders, and could be retrieved by reading theses files, but that is not very convenient. In the following example, we show how to build and solve a JuMP model entirely in-memory, using our trained solver."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "67a6cd18",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:06:26.913448568Z",
"start_time": "2023-06-06T20:06:26.169047914Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x974a7fba\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 1e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [0e+00, 0e+00]\n",
" RHS range [2e+08, 2e+08]\n",
"\n",
"User MIP start produced solution with objective 9.86729e+09 (0.00s)\n",
"User MIP start produced solution with objective 9.86675e+09 (0.00s)\n",
"User MIP start produced solution with objective 9.86654e+09 (0.01s)\n",
"User MIP start produced solution with objective 9.8661e+09 (0.01s)\n",
"Loaded user MIP start with objective 9.8661e+09\n",
"\n",
"Presolve time: 0.00s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
"Root relaxation: objective 9.865344e+09, 510 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 9.8653e+09 0 1 9.8661e+09 9.8653e+09 0.01% - 0s\n",
"\n",
"Explored 1 nodes (510 simplex iterations) in 0.02 seconds (0.01 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 4: 9.8661e+09 9.86654e+09 9.86675e+09 9.86729e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 9.866096485614e+09, best bound 9.865343669936e+09, gap 0.0076%\n",
"\n",
"User-callback calls 182, time in user-callback 0.00 sec\n",
"objective_value(model.inner) = 9.866096485613789e9\n"
]
}
],
"source": [
"data = random_uc_data(samples=1, n=500)[1]\n",
"model = build_uc_model(data)\n",
"solver_ml.optimize(model)\n",
"@show objective_value(model.inner);"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.9.0",
"language": "julia",
"name": "julia-1.9"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.9.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

@ -11,17 +11,17 @@
"\n",
"## Introduction\n",
"\n",
"**MIPLearn** is an open source framework that uses machine learning (ML) to accelerate the performance of both commercial and open source mixed-integer programming solvers (e.g. Gurobi, CPLEX, XPRESS, Cbc or SCIP). In this tutorial, we will:\n",
"**MIPLearn** is an open source framework that uses machine learning (ML) to accelerate the performance of mixed-integer programming solvers (e.g. Gurobi, CPLEX, XPRESS). In this tutorial, we will:\n",
"\n",
"1. Install the Python/Pyomo version of MIPLearn\n",
"2. Model a simple optimization problem using JuMP\n",
"2. Model a simple optimization problem using Pyomo\n",
"3. Generate training data and train the ML models\n",
"4. Use the ML models together Gurobi to solve new instances\n",
"\n",
"<div class=\"alert alert-info\">\n",
"Note\n",
" \n",
"The Python/Pyomo version of MIPLearn is currently only compatible with with Gurobi, CPLEX and XPRESS. For broader solver compatibility, see the Julia/JuMP version of the package.\n",
"The Python/Pyomo version of MIPLearn is currently only compatible with Pyomo persistent solvers (Gurobi, CPLEX and XPRESS). For broader solver compatibility, see the Julia/JuMP version of the package.\n",
"</div>\n",
"\n",
"<div class=\"alert alert-warning\">\n",
@ -41,7 +41,7 @@
"\n",
"MIPLearn is available in two versions:\n",
"\n",
"- Python version, compatible with the Pyomo modeling language,\n",
"- Python version, compatible with the Pyomo and Gurobipy modeling languages,\n",
"- Julia version, compatible with the JuMP modeling language.\n",
"\n",
"In this tutorial, we will demonstrate how to use and install the Python/Pyomo version of the package. The first step is to install Python 3.8+ in your computer. See the [official Python website for more instructions](https://www.python.org/downloads/). After Python is installed, we proceed to install MIPLearn using `pip`:"
@ -51,10 +51,15 @@
"cell_type": "code",
"execution_count": 1,
"id": "cd8a69c1",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T19:57:33.202580815Z",
"start_time": "2023-06-06T19:57:33.198341886Z"
}
},
"outputs": [],
"source": [
"# !pip install MIPLearn==0.2.0.dev13"
"# !pip install MIPLearn==0.3.0"
]
},
{
@ -62,26 +67,30 @@
"id": "e8274543",
"metadata": {},
"source": [
"In addition to MIPLearn itself, we will also install Gurobi 9.5, a state-of-the-art commercial MILP solver. This step also install a demo license for Gurobi, which should able to solve the small optimization problems in this tutorial. A paid license is required for solving large-scale problems."
"In addition to MIPLearn itself, we will also install Gurobi 10.0, a state-of-the-art commercial MILP solver. This step also install a demo license for Gurobi, which should able to solve the small optimization problems in this tutorial. A license is required for solving larger-scale problems."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "dcc8756c",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T19:57:35.756831801Z",
"start_time": "2023-06-06T19:57:33.201767088Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Looking in indexes: https://pypi.gurobi.com\n",
"Requirement already satisfied: gurobipy<9.6,>=9.5 in /opt/anaconda3/envs/miplearn/lib/python3.8/site-packages (9.5.1)\n"
"Requirement already satisfied: gurobipy<10.1,>=10 in /home/axavier/Software/anaconda3/envs/miplearn/lib/python3.8/site-packages (10.0.1)\n"
]
}
],
"source": [
"!pip install --upgrade -i https://pypi.gurobi.com 'gurobipy>=9.5,<9.6'"
"!pip install 'gurobipy>=10,<10.1'"
]
},
{
@ -107,10 +116,16 @@
"\n",
"To illustrate how can MIPLearn be used, we will model and solve a small optimization problem related to power systems optimization. The problem we discuss below is a simplification of the **unit commitment problem,** a practical optimization problem solved daily by electric grid operators around the world. \n",
"\n",
"Suppose that you work at a utility company, and that it is your job to decide which electrical generators should be online at a certain hour of the day, as well as how much power should each generator produce. More specifically, assume that your company owns $n$ generators, denoted by $g_1, \\ldots, g_n$. Each generator can either be online or offline. An online generator $g_i$ can produce between $p^\\text{min}_i$ to $p^\\text{max}_i$ megawatts of power, and it costs your company $c^\\text{fix}_i + c^\\text{var}_i y_i$, where $y_i$ is the amount of power produced. An offline generator produces nothing and costs nothing. You also know that the total amount of power to be produced needs to be exactly equal to the total demand $d$ (in megawatts). To minimize the costs to your company, which generators should be online, and how much power should they produce?\n",
"\n",
"This simple problem can be modeled as a *mixed-integer linear optimization* problem as follows. For each generator $g_i$, let $x_i \\in \\{0,1\\}$ be a decision variable indicating whether $g_i$ is online, and let $y_i \\geq 0$ be a decision variable indicating how much power does $g_i$ produce. The problem is then given by:\n",
"Suppose that a utility company needs to decide which electrical generators should be online at each hour of the day, as well as how much power should each generator produce. More specifically, assume that the company owns $n$ generators, denoted by $g_1, \\ldots, g_n$. Each generator can either be online or offline. An online generator $g_i$ can produce between $p^\\text{min}_i$ to $p^\\text{max}_i$ megawatts of power, and it costs the company $c^\\text{fix}_i + c^\\text{var}_i y_i$, where $y_i$ is the amount of power produced. An offline generator produces nothing and costs nothing. The total amount of power to be produced needs to be exactly equal to the total demand $d$ (in megawatts).\n",
"\n",
"This simple problem can be modeled as a *mixed-integer linear optimization* problem as follows. For each generator $g_i$, let $x_i \\in \\{0,1\\}$ be a decision variable indicating whether $g_i$ is online, and let $y_i \\geq 0$ be a decision variable indicating how much power does $g_i$ produce. The problem is then given by:"
]
},
{
"cell_type": "markdown",
"id": "f12c3702",
"metadata": {},
"source": [
"$$\n",
"\\begin{align}\n",
"\\text{minimize } \\quad & \\sum_{i=1}^n \\left( c^\\text{fix}_i x_i + c^\\text{var}_i y_i \\right) \\\\\n",
@ -120,16 +135,28 @@
"& x_i \\in \\{0,1\\} & i=1,\\ldots,n \\\\\n",
"& y_i \\geq 0 & i=1,\\ldots,n\n",
"\\end{align}\n",
"$$\n",
"\n",
"$$"
]
},
{
"cell_type": "markdown",
"id": "be3989ed",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
" \n",
"\n",
"Note\n",
" \n",
"We use a simplified version of the unit commitment problem in this tutorial just to make it easier to follow. MIPLearn can also handle realistic, large-scale versions of this problem. See benchmarks for more details.\n",
" \n",
"</div>\n",
"\n",
"We use a simplified version of the unit commitment problem in this tutorial just to make it easier to follow. MIPLearn can also handle realistic, large-scale versions of this problem.\n",
"\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "a5fd33f6",
"metadata": {},
"source": [
"Next, let us convert this abstract mathematical formulation into a concrete optimization model, using Python and Pyomo. We start by defining a data class `UnitCommitmentData`, which holds all the input data."
]
},
@ -138,20 +165,27 @@
"execution_count": 3,
"id": "22a67170-10b4-43d3-8708-014d91141e73",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:00:03.278853343Z",
"start_time": "2023-06-06T20:00:03.123324067Z"
},
"tags": []
},
"outputs": [],
"source": [
"from dataclasses import dataclass\n",
"from typing import List\n",
"\n",
"import numpy as np\n",
"\n",
"\n",
"@dataclass\n",
"class UnitCommitmentData:\n",
" demand: float\n",
" pmin: np.ndarray\n",
" pmax: np.ndarray\n",
" cfix: np.ndarray\n",
" cvar: np.ndarray"
" pmin: List[float]\n",
" pmax: List[float]\n",
" cfix: List[float]\n",
" cvar: List[float]"
]
},
{
@ -159,28 +193,38 @@
"id": "29f55efa-0751-465a-9b0a-a821d46a3d40",
"metadata": {},
"source": [
"Next, we write a `build_uc_model` function, which converts the input data into a concrete Pyomo model."
"Next, we write a `build_uc_model` function, which converts the input data into a concrete Pyomo model. The function accepts `UnitCommitmentData`, the data structure we previously defined, or the path to a compressed pickle file containing this data."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "2f67032f-0d74-4317-b45c-19da0ec859e9",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:00:45.890126754Z",
"start_time": "2023-06-06T20:00:45.637044282Z"
}
},
"outputs": [],
"source": [
"import pyomo.environ as pe\n",
"from typing import Union\n",
"from miplearn.io import read_pkl_gz\n",
"from miplearn.solvers.pyomo import PyomoModel\n",
"\n",
"\n",
"def build_uc_model(data: Union[str, UnitCommitmentData]) -> PyomoModel:\n",
" if isinstance(data, str):\n",
" data = read_pkl_gz(data)\n",
"\n",
"def build_uc_model(data: UnitCommitmentData) -> pe.ConcreteModel:\n",
" model = pe.ConcreteModel()\n",
" n = len(data.pmin)\n",
" model.x = pe.Var(range(n), domain=pe.Binary)\n",
" model.y = pe.Var(range(n), domain=pe.NonNegativeReals)\n",
" model.obj = pe.Objective(\n",
" expr=sum(\n",
" data.cfix[i] * model.x[i] +\n",
" data.cvar[i] * model.y[i]\n",
" for i in range(n)\n",
" data.cfix[i] * model.x[i] + data.cvar[i] * model.y[i] for i in range(n)\n",
" )\n",
" )\n",
" model.eq_max_power = pe.ConstraintList()\n",
@ -191,7 +235,7 @@
" model.eq_demand = pe.Constraint(\n",
" expr=sum(model.y[i] for i in range(n)) == data.demand,\n",
" )\n",
" return model"
" return PyomoModel(model, \"gurobi_persistent\")"
]
},
{
@ -206,15 +250,56 @@
"cell_type": "code",
"execution_count": 5,
"id": "2a896f47",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:01:10.993801745Z",
"start_time": "2023-06-06T20:01:10.887580927Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Set parameter Threads to value 1\n",
"Set parameter Seed to value 42\n",
"Restricted license - for non-production use only - expires 2023-10-25\n",
"Restricted license - for non-production use only - expires 2024-10-28\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 7 rows, 6 columns and 15 nonzeros\n",
"Model fingerprint: 0x15c7a953\n",
"Variable types: 3 continuous, 3 integer (3 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 7e+01]\n",
" Objective range [2e+00, 7e+02]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [1e+02, 1e+02]\n",
"Presolve removed 2 rows and 1 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 5 rows, 5 columns, 13 nonzeros\n",
"Variable types: 0 continuous, 5 integer (3 binary)\n",
"Found heuristic solution: objective 1400.0000000\n",
"\n",
"Root relaxation: objective 1.035000e+03, 3 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 1035.00000 0 1 1400.00000 1035.00000 26.1% - 0s\n",
" 0 0 1105.71429 0 1 1400.00000 1105.71429 21.0% - 0s\n",
"* 0 0 0 1320.0000000 1320.00000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (5 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 2: 1320 1400 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 1.320000000000e+03, best bound 1.320000000000e+03, gap 0.0000%\n",
"WARNING: Cannot get reduced costs for MIP.\n",
"WARNING: Cannot get duals for MIP.\n",
"obj = 1320.0\n",
"x = [-0.0, 1.0, 1.0]\n",
"y = [0.0, 60.0, 40.0]\n"
@ -224,20 +309,18 @@
"source": [
"model = build_uc_model(\n",
" UnitCommitmentData(\n",
" demand = 100.0,\n",
" pmin = [10, 20, 30],\n",
" pmax = [50, 60, 70],\n",
" cfix = [700, 600, 500],\n",
" cvar = [1.5, 2.0, 2.5],\n",
" demand=100.0,\n",
" pmin=[10, 20, 30],\n",
" pmax=[50, 60, 70],\n",
" cfix=[700, 600, 500],\n",
" cvar=[1.5, 2.0, 2.5],\n",
" )\n",
")\n",
"\n",
"solver = pe.SolverFactory(\"gurobi_persistent\")\n",
"solver.set_instance(model)\n",
"solver.solve()\n",
"print(\"obj =\", model.obj())\n",
"print(\"x =\", [model.x[i].value for i in range(3)])\n",
"print(\"y =\", [model.y[i].value for i in range(3)])"
"model.optimize()\n",
"print(\"obj =\", model.inner.obj())\n",
"print(\"x =\", [model.inner.x[i].value for i in range(3)])\n",
"print(\"y =\", [model.inner.y[i].value for i in range(3)])"
]
},
{
@ -248,6 +331,20 @@
"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."
]
},
{
"cell_type": "markdown",
"id": "01f576e1-1790-425e-9e5c-9fa07b6f4c26",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
" \n",
"Notes\n",
" \n",
"- In the example above, `PyomoModel` is just a thin wrapper around a standard Pyomo model. This wrapper allows MIPLearn to be solver- and modeling-language-agnostic. The wrapper provides only a few basic methods, such as `optimize`. For more control, and to query the solution, the original Pyomo model can be accessed through `model.inner`, as illustrated above. \n",
"- To use CPLEX or XPRESS, instead of Gurobi, replace `gurobi_persistent` by `cplex_persistent` or `xpress_persistent` in the `build_uc_model`. Note that only persistent Pyomo solvers are currently supported. Pull requests adding support for other types of solver are very welcome.\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "cf60c1dd",
@ -255,7 +352,7 @@
"source": [
"## Generating training data\n",
"\n",
"Although Gurobi could solve the small example above in a fraction of a second, it gets slower for larger and more complex versions of the problem. If this is a problem that needs to be solved frequently, as it is often the case in practice, it could make sense to spend some time upfront generating a **trained** version of Gurobi, which can solve new instances (similar to the ones it was trained on) faster.\n",
"Although Gurobi could solve the small example above in a fraction of a second, it gets slower for larger and more complex versions of the problem. If this is a problem that needs to be solved frequently, as it is often the case in practice, it could make sense to spend some time upfront generating a **trained** solver, which can optimize new instances (similar to the ones it was trained on) faster.\n",
"\n",
"In the following, we will use MIPLearn to train machine learning models that is able to predict the optimal solution for instances that follow a given probability distribution, then it will provide this predicted solution to Gurobi as a warm start. Before we can train the model, we need to collect training data by solving a large number of instances. In real-world situations, we may construct these training instances based on historical data. In this tutorial, we will construct them using a random instance generator:"
]
@ -264,13 +361,19 @@
"cell_type": "code",
"execution_count": 6,
"id": "5eb09fab",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:02:27.324208900Z",
"start_time": "2023-06-06T20:02:26.990044230Z"
}
},
"outputs": [],
"source": [
"from scipy.stats import uniform\n",
"from typing import List\n",
"import random\n",
"\n",
"\n",
"def random_uc_data(samples: int, n: int, seed: int = 42) -> List[UnitCommitmentData]:\n",
" random.seed(seed)\n",
" np.random.seed(seed)\n",
@ -280,13 +383,13 @@
" cvar = uniform(loc=1.25, scale=0.25).rvs(n)\n",
" return [\n",
" UnitCommitmentData(\n",
" demand = pmax.sum() * uniform(loc=0.5, scale=0.25).rvs(),\n",
" pmin = pmin,\n",
" pmax = pmax,\n",
" cfix = cfix,\n",
" cvar = cvar,\n",
" demand=pmax.sum() * uniform(loc=0.5, scale=0.25).rvs(),\n",
" pmin=pmin,\n",
" pmax=pmax,\n",
" cfix=cfix,\n",
" cvar=cvar,\n",
" )\n",
" for i in range(samples)\n",
" for _ in range(samples)\n",
" ]"
]
},
@ -297,20 +400,26 @@
"source": [
"In this example, for simplicity, only the demands change from one instance to the next. We could also have randomized the costs, production limits or even the number of units. 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",
"\n",
"Now we generate 500 instances of this problem, each one with 50 generators, and we use 450 of these instances for training. After generating the instances, we write them to individual files. MIPLearn uses files during the training process because, for large-scale optimization problems, it is often impractical to hold in memory the entire training data, as well as the concrete Pyomo models. 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. The code below generates the files `uc/train/00000.pkl.gz`, `uc/train/00001.pkl.gz`, etc., which contain the input data in compressed (gzipped) pickle format."
"Now we generate 500 instances of this problem, each one with 50 generators, and we use 450 of these instances for training. After generating the instances, we write them to individual files. MIPLearn uses files during the training process because, for large-scale optimization problems, it is often impractical to hold in memory the entire training data, as well as the concrete Pyomo models. Files also make it much easier to solve multiple instances simultaneously, potentially on multiple machines. The code below generates the files `uc/train/00000.pkl.gz`, `uc/train/00001.pkl.gz`, etc., which contain the input data in compressed (gzipped) pickle format."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "6156752c",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:03:04.782830561Z",
"start_time": "2023-06-06T20:03:04.530421396Z"
}
},
"outputs": [],
"source": [
"from miplearn import save\n",
"data = random_uc_data(samples=500, n=50)\n",
"train_files = save(data[0:450], \"uc/train/\")\n",
"test_files = save(data[450:500], \"uc/test/\")"
"from miplearn.io import write_pkl_gz\n",
"\n",
"data = random_uc_data(samples=500, n=500)\n",
"train_data = write_pkl_gz(data[0:450], \"uc/train\")\n",
"test_data = write_pkl_gz(data[450:500], \"uc/test\")"
]
},
{
@ -318,115 +427,180 @@
"id": "b17af877",
"metadata": {},
"source": [
"Finally, we use `LearningSolver` to solve all the training instances. `LearningSolver` is the main component provided by MIPLearn, which integrates MIP solvers and ML. The optimal solutions, along with other useful training data, are stored in HDF5 files `uc/train/00000.h5`, `uc/train/00001.h5`, etc."
"Finally, we use `BasicCollector` to collect the optimal solutions and other useful training data for all training instances. The data is stored in HDF5 files `uc/train/00000.h5`, `uc/train/00001.h5`, etc. The optimization models are also exported to compressed MPS files `uc/train/00000.mps.gz`, `uc/train/00001.mps.gz`, etc."
]
},
{
"cell_type": "code",
"execution_count": 12,
"execution_count": 8,
"id": "7623f002",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:03:35.571497019Z",
"start_time": "2023-06-06T20:03:25.804104036Z"
}
},
"outputs": [],
"source": [
"from miplearn import LearningSolver\n",
"solver = LearningSolver()\n",
"solver.solve(train_files, build_uc_model);"
"from miplearn.collectors.basic import BasicCollector\n",
"\n",
"bc = BasicCollector()\n",
"bc.collect(train_data, build_uc_model, n_jobs=4)"
]
},
{
"cell_type": "markdown",
"id": "2f24ee83",
"id": "c42b1be1-9723-4827-82d8-974afa51ef9f",
"metadata": {},
"source": [
"## Solving test instances\n",
"## Training and solving test instances"
]
},
{
"cell_type": "markdown",
"id": "a33c6aa4-f0b8-4ccb-9935-01f7d7de2a1c",
"metadata": {},
"source": [
"With training data in hand, we can now design and train a machine learning model to accelerate solver performance. In this tutorial, for illustration purposes, we will use ML to generate a good warm start using $k$-nearest neighbors. More specifically, the strategy is to:\n",
"\n",
"1. Memorize the optimal solutions of all training instances;\n",
"2. Given a test instance, find the 25 most similar training instances, based on constraint right-hand sides;\n",
"3. Merge their optimal solutions into a single partial solution; specifically, only assign values to the binary variables that agree unanimously.\n",
"4. Provide this partial solution to the solver as a warm start.\n",
"\n",
"With training data in hand, we can now fit the ML models, using the `LearningSolver.fit` method, then solve the test instances with `LearningSolver.solve`, as shown below. The `tee=True` parameter asks MIPLearn to print the solver log to the screen."
"This simple strategy can be implemented as shown below, using `MemorizingPrimalComponent`. For more advanced strategies, and for the usage of more advanced classifiers, see the user guide."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "c8385030",
"id": "435f7bf8-4b09-4889-b1ec-b7b56e7d8ed2",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:05:20.497772794Z",
"start_time": "2023-06-06T20:05:20.484821405Z"
}
},
"outputs": [],
"source": [
"from sklearn.neighbors import KNeighborsClassifier\n",
"from miplearn.components.primal.actions import SetWarmStart\n",
"from miplearn.components.primal.mem import (\n",
" MemorizingPrimalComponent,\n",
" MergeTopSolutions,\n",
")\n",
"from miplearn.extractors.fields import H5FieldsExtractor\n",
"\n",
"comp = MemorizingPrimalComponent(\n",
" clf=KNeighborsClassifier(n_neighbors=25),\n",
" extractor=H5FieldsExtractor(\n",
" instance_fields=[\"static_constr_rhs\"],\n",
" ),\n",
" constructor=MergeTopSolutions(25, [0.0, 1.0]),\n",
" action=SetWarmStart(),\n",
")"
]
},
{
"cell_type": "markdown",
"id": "9536e7e4-0b0d-49b0-bebd-4a848f839e94",
"metadata": {},
"source": [
"Having defined the ML strategy, we next construct `LearningSolver`, train the ML component and optimize one of the test instances."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "9d13dd50-3dcf-4673-a757-6f44dcc0dedf",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:05:22.672002339Z",
"start_time": "2023-06-06T20:05:21.447466634Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Set parameter LogFile to value \"/tmp/tmpvbaqbyty.log\"\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 9.5.1 build v9.5.1rc2 (linux64)\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 1 threads\n",
"Optimize a model with 101 rows, 100 columns and 250 nonzeros\n",
"Model fingerprint: 0x8de73876\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x5e67c6ee\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [2e+07, 2e+07]\n",
"Presolve removed 100 rows and 50 columns\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 1 rows, 50 columns, 50 nonzeros\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
" 0 5.7349081e+08 1.044003e+04 0.000000e+00 0s\n",
" 1 6.8268465e+08 0.000000e+00 0.000000e+00 0s\n",
"\n",
"Solved in 1 iterations and 0.00 seconds (0.00 work units)\n",
"Optimal objective 6.826846503e+08\n",
"Set parameter LogFile to value \"\"\n",
"Set parameter LogFile to value \"/tmp/tmp48j6n35b.log\"\n",
"Gurobi Optimizer version 9.5.1 build v9.5.1rc2 (linux64)\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 1 threads\n",
"Optimize a model with 101 rows, 100 columns and 250 nonzeros\n",
"Model fingerprint: 0x200d64ba\n",
"Variable types: 50 continuous, 50 integer (50 binary)\n",
" 0 6.6166537e+09 5.648803e+04 0.000000e+00 0s\n",
" 1 8.2906219e+09 0.000000e+00 0.000000e+00 0s\n",
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.290621916e+09\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0xa4a7961e\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [2e+07, 2e+07]\n",
" RHS range [3e+08, 3e+08]\n",
"\n",
"User MIP start produced solution with objective 6.84841e+08 (0.00s)\n",
"Loaded user MIP start with objective 6.84841e+08\n",
"User MIP start produced solution with objective 8.30129e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29184e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29146e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29146e+09 (0.02s)\n",
"Loaded user MIP start with objective 8.29146e+09\n",
"\n",
"Presolve time: 0.00s\n",
"Presolved: 101 rows, 100 columns, 250 nonzeros\n",
"Variable types: 50 continuous, 50 integer (50 binary)\n",
"Presolve time: 0.01s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
"Root relaxation: objective 6.826847e+08, 56 iterations, 0.00 seconds (0.00 work units)\n",
"Root relaxation: objective 8.290622e+09, 512 iterations, 0.01 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 6.8268e+08 0 1 6.8484e+08 6.8268e+08 0.31% - 0s\n",
" 0 0 6.8315e+08 0 3 6.8484e+08 6.8315e+08 0.25% - 0s\n",
" 0 0 6.8315e+08 0 1 6.8484e+08 6.8315e+08 0.25% - 0s\n",
" 0 0 6.8315e+08 0 3 6.8484e+08 6.8315e+08 0.25% - 0s\n",
" 0 0 6.8315e+08 0 4 6.8484e+08 6.8315e+08 0.25% - 0s\n",
" 0 0 6.8315e+08 0 4 6.8484e+08 6.8315e+08 0.25% - 0s\n",
" 0 2 6.8327e+08 0 4 6.8484e+08 6.8327e+08 0.23% - 0s\n",
" 0 0 8.2906e+09 0 1 8.2915e+09 8.2906e+09 0.01% - 0s\n",
"\n",
"Cutting planes:\n",
" Flow cover: 3\n",
" Cover: 1\n",
" Flow cover: 2\n",
"\n",
"Explored 32 nodes (155 simplex iterations) in 0.02 seconds (0.00 work units)\n",
"Thread count was 1 (of 32 available processors)\n",
"Explored 1 nodes (512 simplex iterations) in 0.09 seconds (0.01 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 1: 6.84841e+08 \n",
"Solution count 3: 8.29146e+09 8.29184e+09 8.30129e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 6.848411655488e+08, best bound 6.848411655488e+08, gap 0.0000%\n",
"Set parameter LogFile to value \"\"\n",
"Best objective 8.291459497797e+09, best bound 8.290645029670e+09, gap 0.0098%\n",
"WARNING: Cannot get reduced costs for MIP.\n",
"WARNING: Cannot get duals for MIP.\n"
]
}
],
"source": [
"solver_ml = LearningSolver()\n",
"solver_ml.fit(train_files, build_uc_model)\n",
"solver_ml.solve(test_files[0:1], build_uc_model, tee=True);"
"from miplearn.solvers.learning import LearningSolver\n",
"\n",
"solver_ml = LearningSolver(components=[comp])\n",
"solver_ml.fit(train_data)\n",
"solver_ml.optimize(test_data[0], build_uc_model);"
]
},
{
@ -434,100 +608,105 @@
"id": "61da6dad-7f56-4edb-aa26-c00eb5f946c0",
"metadata": {},
"source": [
"By examining the solve log above, specifically the line `Loaded user MIP start with objective...`, we can see that MIPLearn was able to construct an initial solution which turned out to be the optimal solution to the problem. Now let us repeat the code above, but using an untrained solver. Note that the `fit` line is omitted."
"By examining the solve log above, specifically the line `Loaded user MIP start with objective...`, we can see that MIPLearn was able to construct an initial solution which turned out to be very close to the optimal solution to the problem. Now let us repeat the code above, but a solver which does not apply any ML strategies. Note that our previously-defined component is not provided."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "33d15d6c-6db4-477f-bd4b-fe8e84e5f023",
"metadata": {},
"execution_count": 11,
"id": "2ff391ed-e855-4228-aa09-a7641d8c2893",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:05:46.969575966Z",
"start_time": "2023-06-06T20:05:46.420803286Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Set parameter LogFile to value \"/tmp/tmp3uhhdurw.log\"\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 9.5.1 build v9.5.1rc2 (linux64)\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 1 threads\n",
"Optimize a model with 101 rows, 100 columns and 250 nonzeros\n",
"Model fingerprint: 0x8de73876\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x5e67c6ee\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [2e+07, 2e+07]\n",
"Presolve removed 100 rows and 50 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 1 rows, 50 columns, 50 nonzeros\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.01s\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
" 0 5.7349081e+08 1.044003e+04 0.000000e+00 0s\n",
" 1 6.8268465e+08 0.000000e+00 0.000000e+00 0s\n",
" 0 6.6166537e+09 5.648803e+04 0.000000e+00 0s\n",
" 1 8.2906219e+09 0.000000e+00 0.000000e+00 0s\n",
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 6.826846503e+08\n",
"Set parameter LogFile to value \"\"\n",
"Set parameter LogFile to value \"/tmp/tmp18aqg2ic.log\"\n",
"Gurobi Optimizer version 9.5.1 build v9.5.1rc2 (linux64)\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 1 threads\n",
"Optimize a model with 101 rows, 100 columns and 250 nonzeros\n",
"Model fingerprint: 0xb90d1075\n",
"Variable types: 50 continuous, 50 integer (50 binary)\n",
"Optimal objective 8.290621916e+09\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x8a0f9587\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [2e+07, 2e+07]\n",
"Found heuristic solution: objective 8.056576e+08\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve time: 0.00s\n",
"Presolved: 101 rows, 100 columns, 250 nonzeros\n",
"Variable types: 50 continuous, 50 integer (50 binary)\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Found heuristic solution: objective 9.757128e+09\n",
"\n",
"Root relaxation: objective 6.826847e+08, 56 iterations, 0.00 seconds (0.00 work units)\n",
"Root relaxation: objective 8.290622e+09, 512 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 6.8268e+08 0 1 8.0566e+08 6.8268e+08 15.3% - 0s\n",
"H 0 0 7.099498e+08 6.8268e+08 3.84% - 0s\n",
" 0 0 6.8315e+08 0 3 7.0995e+08 6.8315e+08 3.78% - 0s\n",
"H 0 0 6.883227e+08 6.8315e+08 0.75% - 0s\n",
" 0 0 6.8352e+08 0 4 6.8832e+08 6.8352e+08 0.70% - 0s\n",
" 0 0 6.8352e+08 0 4 6.8832e+08 6.8352e+08 0.70% - 0s\n",
" 0 0 6.8352e+08 0 1 6.8832e+08 6.8352e+08 0.70% - 0s\n",
"H 0 0 6.862582e+08 6.8352e+08 0.40% - 0s\n",
" 0 0 6.8352e+08 0 4 6.8626e+08 6.8352e+08 0.40% - 0s\n",
" 0 0 6.8352e+08 0 4 6.8626e+08 6.8352e+08 0.40% - 0s\n",
" 0 0 6.8352e+08 0 1 6.8626e+08 6.8352e+08 0.40% - 0s\n",
" 0 0 6.8352e+08 0 3 6.8626e+08 6.8352e+08 0.40% - 0s\n",
" 0 0 6.8352e+08 0 4 6.8626e+08 6.8352e+08 0.40% - 0s\n",
" 0 0 6.8352e+08 0 4 6.8626e+08 6.8352e+08 0.40% - 0s\n",
" 0 2 6.8354e+08 0 4 6.8626e+08 6.8354e+08 0.40% - 0s\n",
"* 18 5 6 6.849018e+08 6.8413e+08 0.11% 3.1 0s\n",
"H 24 1 6.848412e+08 6.8426e+08 0.09% 3.2 0s\n",
" 0 0 8.2906e+09 0 1 9.7571e+09 8.2906e+09 15.0% - 0s\n",
"H 0 0 8.298273e+09 8.2906e+09 0.09% - 0s\n",
" 0 0 8.2907e+09 0 4 8.2983e+09 8.2907e+09 0.09% - 0s\n",
" 0 0 8.2907e+09 0 1 8.2983e+09 8.2907e+09 0.09% - 0s\n",
" 0 0 8.2907e+09 0 4 8.2983e+09 8.2907e+09 0.09% - 0s\n",
"H 0 0 8.293980e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2907e+09 0 5 8.2940e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2907e+09 0 1 8.2940e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2907e+09 0 2 8.2940e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2908e+09 0 1 8.2940e+09 8.2908e+09 0.04% - 0s\n",
" 0 0 8.2908e+09 0 4 8.2940e+09 8.2908e+09 0.04% - 0s\n",
" 0 0 8.2908e+09 0 4 8.2940e+09 8.2908e+09 0.04% - 0s\n",
"H 0 0 8.291465e+09 8.2908e+09 0.01% - 0s\n",
"\n",
"Cutting planes:\n",
" Gomory: 1\n",
" Flow cover: 2\n",
" Gomory: 2\n",
" MIR: 1\n",
"\n",
"Explored 30 nodes (217 simplex iterations) in 0.02 seconds (0.00 work units)\n",
"Thread count was 1 (of 32 available processors)\n",
"Explored 1 nodes (1025 simplex iterations) in 0.08 seconds (0.03 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 6: 6.84841e+08 6.84902e+08 6.86258e+08 ... 8.05658e+08\n",
"Solution count 4: 8.29147e+09 8.29398e+09 8.29827e+09 9.75713e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 6.848411655488e+08, best bound 6.848411655488e+08, gap 0.0000%\n",
"Set parameter LogFile to value \"\"\n",
"Best objective 8.291465302389e+09, best bound 8.290781665333e+09, gap 0.0082%\n",
"WARNING: Cannot get reduced costs for MIP.\n",
"WARNING: Cannot get duals for MIP.\n"
]
}
],
"source": [
"solver_baseline = LearningSolver()\n",
"solver_baseline.solve(test_files[0:1], build_uc_model, tee=True);"
"solver_baseline = LearningSolver(components=[])\n",
"solver_baseline.fit(train_data)\n",
"solver_baseline.optimize(test_data[0], build_uc_model);"
]
},
{
@ -535,19 +714,7 @@
"id": "b6d37b88-9fcc-43ee-ac1e-2a7b1e51a266",
"metadata": {},
"source": [
"In the log above, the `MIP start` line is missing, and Gurobi had to start with a significantly inferior initial solution. The solver was still able to find the optimal solution at the end, but it required using its own internal heuristic procedures. In this example, because we solve very small optimization problems, there was almost no difference in terms of running time. For larger problems, however, the difference can be significant. See benchmarks for more details.\n",
"\n",
"<div class=\"alert alert-info\">\n",
"Note\n",
" \n",
"In addition to partial initial solutions, MIPLearn is also able to predict lazy constraints, cutting planes and branching priorities. See the next tutorials for more details.\n",
"</div>\n",
"\n",
"<div class=\"alert alert-info\">\n",
"Note\n",
" \n",
"It is not necessary to specify what ML models to use. MIPLearn, by default, will try a number of classical ML models and will choose the one that performs the best, based on k-fold cross validation. MIPLearn is also able to automatically collect features based on the MIP formulation of the problem and the solution to the LP relaxation, among other things, so it does not require handcrafted features. If you do want to customize the models and features, however, that is also possible, as we will see in a later tutorial.\n",
"</div>"
"In the log above, the `MIP start` line is missing, and Gurobi had to start with a significantly inferior initial solution. The solver was still able to find the optimal solution at the end, but it required using its own internal heuristic procedures. In this example, because we solve very small optimization problems, there was almost no difference in terms of running time, but the difference can be significant for larger problems."
]
},
{
@ -564,32 +731,109 @@
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": 12,
"id": "67a6cd18",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:06:26.913448568Z",
"start_time": "2023-06-06T20:06:26.169047914Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"obj = 903865807.3536932\n",
" x = [1.0, 1.0, 1.0, 1.0, 1.0]\n",
" y = [1105176.593734543, 1891284.5155055337, 1708177.4224033852, 1438329.610189608, 535496.3347187206]\n"
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x2dfe4e1c\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.01s\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
" 0 6.5917580e+09 5.627453e+04 0.000000e+00 0s\n",
" 1 8.2535968e+09 0.000000e+00 0.000000e+00 0s\n",
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.253596777e+09\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x20637200\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"\n",
"User MIP start produced solution with objective 8.25814e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25512e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.04s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.04s)\n",
"Loaded user MIP start with objective 8.25459e+09\n",
"\n",
"Presolve time: 0.01s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
"Root relaxation: objective 8.253597e+09, 512 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 8.2536e+09 0 1 8.2546e+09 8.2536e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 3 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 1 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 4 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 4 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2538e+09 0 4 8.2546e+09 8.2538e+09 0.01% - 0s\n",
" 0 0 8.2538e+09 0 5 8.2546e+09 8.2538e+09 0.01% - 0s\n",
" 0 0 8.2538e+09 0 6 8.2546e+09 8.2538e+09 0.01% - 0s\n",
"\n",
"Cutting planes:\n",
" Cover: 1\n",
" MIR: 2\n",
" StrongCG: 1\n",
" Flow cover: 1\n",
"\n",
"Explored 1 nodes (575 simplex iterations) in 0.11 seconds (0.01 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 3: 8.25459e+09 8.25512e+09 8.25814e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 8.254590409970e+09, best bound 8.253768093811e+09, gap 0.0100%\n",
"WARNING: Cannot get reduced costs for MIP.\n",
"WARNING: Cannot get duals for MIP.\n",
"obj = 8254590409.96973\n",
" x = [1.0, 1.0, 0.0, 1.0, 1.0]\n",
" y = [935662.0949263407, 1604270.0218116897, 0.0, 1369560.835229226, 602828.5321028307]\n"
]
}
],
"source": [
"# Construct model using previously defined functions\n",
"data = random_uc_data(samples=1, n=50)[0]\n",
"data = random_uc_data(samples=1, n=500)[0]\n",
"model = build_uc_model(data)\n",
"\n",
"# Solve model using ML + Gurobi\n",
"solver_ml.solve(model)\n",
"\n",
"# Print part of the optimal solution\n",
"print(\"obj =\", model.obj())\n",
"print(\" x =\", [model.x[i].value for i in range(5)])\n",
"print(\" y =\", [model.y[i].value for i in range(5)])"
"solver_ml.optimize(model)\n",
"print(\"obj =\", model.inner.obj())\n",
"print(\" x =\", [model.inner.x[i].value for i in range(5)])\n",
"print(\" y =\", [model.inner.y[i].value for i in range(5)])"
]
},
{
@ -603,7 +847,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<style>
svg { fill: lightcoral; }
@media (prefers-color-scheme: dark) {
svg { fill: crimson; }
}
</style>
<path d="m 80.856887,38.34474 h 2.903414 l 7.066397,13.332221 V 38.34474 h 2.092166 V 54.281494 H 90.01545 L 82.949053,40.949273 v 13.332221 h -2.092166 z m -13.812565,0 h 10.076555 v 1.814633 h -7.920343 v 4.718048 h 7.589439 v 1.814634 h -7.589439 v 5.774805 h 8.11248 v 1.814634 H 67.044322 Z m -14.335606,0 h 2.156212 v 6.735493 L 62.01672,38.34474 h 2.775323 l -7.909669,7.429324 8.475407,8.50743 h -2.839368 l -7.653485,-7.674833 v 7.674833 h -2.156212 z m -10.738365,1.462381 q -2.348349,0 -3.73601,1.750588 -1.376987,1.750588 -1.376987,4.771419 0,3.010158 1.376987,4.760746 1.387661,1.750587 3.73601,1.750587 2.34835,0 3.714663,-1.750587 1.376986,-1.750588 1.376986,-4.760746 0,-3.020831 -1.376986,-4.771419 -1.366313,-1.750588 -3.714663,-1.750588 z m 0,-1.750588 q 3.351736,0 5.358507,2.252281 2.006772,2.241606 2.006772,6.020314 0,3.768034 -2.006772,6.020315 -2.006771,2.241606 -5.358507,2.241606 -3.362409,0 -5.379855,-2.241606 -2.006772,-2.241607 -2.006772,-6.020315 0,-3.778708 2.006772,-6.020314 2.017446,-2.252281 5.379855,-2.252281 z m -14.100771,8.75294 q 0.693831,0.234835 1.344964,1.003385 0.661808,0.768551 1.323615,2.113515 l 2.188235,4.355121 H 30.410068 L 28.371273,50.193231 Q 27.581374,48.592083 26.834172,48.069042 26.097644,47.546 24.816726,47.546 h -2.34835 v 6.735494 H 20.312164 V 38.34474 h 4.867489 q 2.732625,0 4.077588,1.142152 1.344964,1.142151 1.344964,3.447804 0,1.505078 -0.704505,2.49779 -0.69383,0.992711 -2.02812,1.376987 z m -5.401204,-6.692797 v 5.657388 h 2.711277 q 1.55845,0 2.348349,-0.715179 0.800574,-0.725854 0.800574,-2.124189 0,-1.398336 -0.800574,-2.102841 -0.789899,-0.715179 -2.348349,-0.715179 z M 7.4709616,46.670707 v 5.838851 H 10.92944 q 1.739914,0 2.57251,-0.71518 0.843271,-0.725853 0.843271,-2.209583 0,-1.494404 -0.843271,-2.198909 -0.832596,-0.715179 -2.57251,-0.715179 z m 0,-6.554031 v 4.803443 h 3.1916204 q 1.579799,0 2.34835,-0.587088 0.779225,-0.597761 0.779225,-1.814634 0,-1.206197 -0.779225,-1.803959 -0.768551,-0.597762 -2.34835,-0.597762 z M 5.3147497,38.34474 h 5.5079473 q 2.465767,0 3.800057,1.024734 1.334289,1.024734 1.334289,2.914088 0,1.462382 -0.683156,2.327001 -0.683156,0.86462 -2.006772,1.078106 1.590474,0.341579 2.465768,1.430359 0.885968,1.078106 0.885968,2.700602 0,2.134863 -1.451707,3.298364 -1.451707,1.1635 -4.130961,1.1635 H 5.3147497 Z M 65.365328,74.550032 H 67.52154 V 88.67217 h 7.760238 v 1.814634 h -9.91645 z m -6.447298,0 h 2.156214 V 90.486804 H 58.91803 Z m -9.955303,2.124192 -2.924765,7.931025 h 5.860208 z m -1.216872,-2.124192 h 2.444423 l 6.073692,15.936772 h -2.241606 l -1.451709,-4.088268 h -7.183824 l -1.451707,4.088268 H 41.66149 Z m -21.264514,0 h 2.903417 L 36.45116,87.882271 V 74.550032 h 2.092171 V 90.486804 H 35.639914 L 28.573506,77.154569 v 13.332235 h -2.092165 z m 53.454813,-9.781663 v 5.838858 h 3.458479 q 1.739919,0 2.572513,-0.71518 0.843272,-0.725854 0.843272,-2.209586 0,-1.494406 -0.843272,-2.198912 -0.832594,-0.71518 -2.572513,-0.71518 z m 0,-6.554037 v 4.803447 h 3.191622 q 1.579803,0 2.348355,-0.587087 0.779225,-0.597763 0.779225,-1.814636 0,-1.206199 -0.779225,-1.803962 -0.768552,-0.597762 -2.348355,-0.597762 z m -2.156212,-1.771939 h 5.507949 q 2.465772,0 3.800065,1.024736 1.334288,1.024735 1.334288,2.914092 0,1.462383 -0.683157,2.327003 -0.683157,0.864621 -2.006771,1.078107 1.590471,0.341579 2.46577,1.43036 0.885967,1.078107 0.885967,2.700605 0,2.134866 -1.451708,3.298368 -1.451709,1.163502 -4.130963,1.163502 h -5.72144 z m -18.86154,0 h 3.212969 l 4.066921,10.845118 4.088269,-10.845118 H 73.49953 V 72.379166 H 71.396692 V 58.385121 L 67.287075,69.315634 H 65.120183 L 61.010567,58.385121 v 13.994045 h -2.092165 z m -16.246333,0 h 2.166892 v 9.681616 q 0,2.561839 0.928668,3.693318 0.928667,1.120804 3.010159,1.120804 2.070819,0 2.999486,-1.120804 0.928667,-1.131479 0.928667,-3.693318 v -9.681616 h 2.166886 v 9.948474 q 0,3.116904 -1.547776,4.70738 -1.537104,1.590474 -4.547263,1.590474 -3.020833,0 -4.568615,-1.590474 -1.537104,-1.590476 -1.537104,-4.70738 z m -16.192953,0 h 2.156213 v 6.532689 h 7.83496 v -6.532689 h 2.156213 v 15.936773 h -2.156213 v -7.589448 h -7.83496 v 7.589448 h -2.156213 z m -15.563168,0 h 13.481671 v 1.814636 H 18.740226 V 72.379166 H 16.573339 V 58.257029 h -5.657391 z" />
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

@ -0,0 +1,259 @@
/* remove conflicting styling from Sphinx themes */
div.nbinput.container div.prompt *,
div.nboutput.container div.prompt *,
div.nbinput.container div.input_area pre,
div.nboutput.container div.output_area pre,
div.nbinput.container div.input_area .highlight,
div.nboutput.container div.output_area .highlight {
border: none;
padding: 0;
margin: 0;
box-shadow: none;
}
div.nbinput.container > div[class*=highlight],
div.nboutput.container > div[class*=highlight] {
margin: 0;
}
div.nbinput.container div.prompt *,
div.nboutput.container div.prompt * {
background: none;
}
div.nboutput.container div.output_area .highlight,
div.nboutput.container div.output_area pre {
background: unset;
}
div.nboutput.container div.output_area div.highlight {
color: unset; /* override Pygments text color */
}
/* avoid gaps between output lines */
div.nboutput.container div[class*=highlight] pre {
line-height: normal;
}
/* input/output containers */
div.nbinput.container,
div.nboutput.container {
display: -webkit-flex;
display: flex;
align-items: flex-start;
margin: 0;
width: 100%;
}
@media (max-width: 540px) {
div.nbinput.container,
div.nboutput.container {
flex-direction: column;
}
}
/* input container */
div.nbinput.container {
padding-top: 5px;
}
/* last container */
div.nblast.container {
padding-bottom: 5px;
}
/* input prompt */
div.nbinput.container div.prompt pre,
/* for sphinx_immaterial theme: */
div.nbinput.container div.prompt pre > code {
color: #307FC1;
}
/* output prompt */
div.nboutput.container div.prompt pre,
/* for sphinx_immaterial theme: */
div.nboutput.container div.prompt pre > code {
color: #BF5B3D;
}
/* all prompts */
div.nbinput.container div.prompt,
div.nboutput.container div.prompt {
width: 4.5ex;
padding-top: 5px;
position: relative;
user-select: none;
}
div.nbinput.container div.prompt > div,
div.nboutput.container div.prompt > div {
position: absolute;
right: 0;
margin-right: 0.3ex;
}
@media (max-width: 540px) {
div.nbinput.container div.prompt,
div.nboutput.container div.prompt {
width: unset;
text-align: left;
padding: 0.4em;
}
div.nboutput.container div.prompt.empty {
padding: 0;
}
div.nbinput.container div.prompt > div,
div.nboutput.container div.prompt > div {
position: unset;
}
}
/* disable scrollbars and line breaks on prompts */
div.nbinput.container div.prompt pre,
div.nboutput.container div.prompt pre {
overflow: hidden;
white-space: pre;
}
/* input/output area */
div.nbinput.container div.input_area,
div.nboutput.container div.output_area {
-webkit-flex: 1;
flex: 1;
overflow: auto;
}
@media (max-width: 540px) {
div.nbinput.container div.input_area,
div.nboutput.container div.output_area {
width: 100%;
}
}
/* input area */
div.nbinput.container div.input_area {
border: 1px solid #e0e0e0;
border-radius: 2px;
/*background: #f5f5f5;*/
}
/* override MathJax center alignment in output cells */
div.nboutput.container div[class*=MathJax] {
text-align: left !important;
}
/* override sphinx.ext.imgmath center alignment in output cells */
div.nboutput.container div.math p {
text-align: left;
}
/* standard error */
div.nboutput.container div.output_area.stderr {
background: #fdd;
}
/* ANSI colors */
.ansi-black-fg { color: #3E424D; }
.ansi-black-bg { background-color: #3E424D; }
.ansi-black-intense-fg { color: #282C36; }
.ansi-black-intense-bg { background-color: #282C36; }
.ansi-red-fg { color: #E75C58; }
.ansi-red-bg { background-color: #E75C58; }
.ansi-red-intense-fg { color: #B22B31; }
.ansi-red-intense-bg { background-color: #B22B31; }
.ansi-green-fg { color: #00A250; }
.ansi-green-bg { background-color: #00A250; }
.ansi-green-intense-fg { color: #007427; }
.ansi-green-intense-bg { background-color: #007427; }
.ansi-yellow-fg { color: #DDB62B; }
.ansi-yellow-bg { background-color: #DDB62B; }
.ansi-yellow-intense-fg { color: #B27D12; }
.ansi-yellow-intense-bg { background-color: #B27D12; }
.ansi-blue-fg { color: #208FFB; }
.ansi-blue-bg { background-color: #208FFB; }
.ansi-blue-intense-fg { color: #0065CA; }
.ansi-blue-intense-bg { background-color: #0065CA; }
.ansi-magenta-fg { color: #D160C4; }
.ansi-magenta-bg { background-color: #D160C4; }
.ansi-magenta-intense-fg { color: #A03196; }
.ansi-magenta-intense-bg { background-color: #A03196; }
.ansi-cyan-fg { color: #60C6C8; }
.ansi-cyan-bg { background-color: #60C6C8; }
.ansi-cyan-intense-fg { color: #258F8F; }
.ansi-cyan-intense-bg { background-color: #258F8F; }
.ansi-white-fg { color: #C5C1B4; }
.ansi-white-bg { background-color: #C5C1B4; }
.ansi-white-intense-fg { color: #A1A6B2; }
.ansi-white-intense-bg { background-color: #A1A6B2; }
.ansi-default-inverse-fg { color: #FFFFFF; }
.ansi-default-inverse-bg { background-color: #000000; }
.ansi-bold { font-weight: bold; }
.ansi-underline { text-decoration: underline; }
div.nbinput.container div.input_area div[class*=highlight] > pre,
div.nboutput.container div.output_area div[class*=highlight] > pre,
div.nboutput.container div.output_area div[class*=highlight].math,
div.nboutput.container div.output_area.rendered_html,
div.nboutput.container div.output_area > div.output_javascript,
div.nboutput.container div.output_area:not(.rendered_html) > img{
padding: 5px;
margin: 0;
}
/* fix copybtn overflow problem in chromium (needed for 'sphinx_copybutton') */
div.nbinput.container div.input_area > div[class^='highlight'],
div.nboutput.container div.output_area > div[class^='highlight']{
overflow-y: hidden;
}
/* hide copy button on prompts for 'sphinx_copybutton' extension ... */
.prompt .copybtn,
/* ... and 'sphinx_immaterial' theme */
.prompt .md-clipboard.md-icon {
display: none;
}
/* Some additional styling taken form the Jupyter notebook CSS */
.jp-RenderedHTMLCommon table,
div.rendered_html table {
border: none;
border-collapse: collapse;
border-spacing: 0;
color: black;
font-size: 12px;
table-layout: fixed;
}
.jp-RenderedHTMLCommon thead,
div.rendered_html thead {
border-bottom: 1px solid black;
vertical-align: bottom;
}
.jp-RenderedHTMLCommon tr,
.jp-RenderedHTMLCommon th,
.jp-RenderedHTMLCommon td,
div.rendered_html tr,
div.rendered_html th,
div.rendered_html td {
text-align: right;
vertical-align: middle;
padding: 0.5em 0.5em;
line-height: normal;
white-space: normal;
max-width: none;
border: none;
}
.jp-RenderedHTMLCommon th,
div.rendered_html th {
font-weight: bold;
}
.jp-RenderedHTMLCommon tbody tr:nth-child(odd),
div.rendered_html tbody tr:nth-child(odd) {
background: #f5f5f5;
}
.jp-RenderedHTMLCommon tbody tr:hover,
div.rendered_html tbody tr:hover {
background: rgba(66, 165, 245, 0.2);
}

@ -0,0 +1,31 @@
.nbsphinx-gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 5px;
margin-top: 1em;
margin-bottom: 1em;
}
.nbsphinx-gallery > a {
padding: 5px;
border: 1px dotted currentColor;
border-radius: 2px;
text-align: center;
}
.nbsphinx-gallery > a:hover {
border-style: solid;
}
.nbsphinx-gallery img {
max-width: 100%;
max-height: 100%;
}
.nbsphinx-gallery > a > div:first-child {
display: flex;
align-items: start;
justify-content: center;
height: 120px;
margin-bottom: 5px;
}

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<style>
svg { fill: #ccc; }
@media (prefers-color-scheme: dark) {
svg { fill: #999; }
}
</style>
<path d="M 65.365328,74.550032 H 67.52154 V 88.67217 h 7.760238 v 1.814634 h -9.91645 z m -6.447298,0 h 2.156214 V 90.486804 H 58.91803 Z m -9.955303,2.124192 -2.924765,7.931025 h 5.860208 z m -1.216872,-2.124192 h 2.444423 l 6.073692,15.936772 h -2.241606 l -1.451709,-4.088268 h -7.183824 l -1.451707,4.088268 H 41.66149 Z m -21.264514,0 h 2.903417 L 36.45116,87.882271 V 74.550032 h 2.092171 V 90.486804 H 35.639914 L 28.573506,77.154569 v 13.332235 h -2.092165 z m 53.454813,-9.781663 v 5.838858 h 3.458479 q 1.739919,0 2.572513,-0.71518 0.843272,-0.725854 0.843272,-2.209586 0,-1.494406 -0.843272,-2.198912 -0.832594,-0.71518 -2.572513,-0.71518 z m 0,-6.554037 v 4.803447 h 3.191622 q 1.579803,0 2.348355,-0.587087 0.779225,-0.597763 0.779225,-1.814636 0,-1.206199 -0.779225,-1.803962 -0.768552,-0.597762 -2.348355,-0.597762 z m -2.156212,-1.771939 h 5.507949 q 2.465772,0 3.800065,1.024736 1.334288,1.024735 1.334288,2.914092 0,1.462383 -0.683157,2.327003 -0.683157,0.864621 -2.006771,1.078107 1.590471,0.341579 2.46577,1.43036 0.885967,1.078107 0.885967,2.700605 0,2.134866 -1.451708,3.298368 -1.451709,1.163502 -4.130963,1.163502 h -5.72144 z m -18.86154,0 h 3.212969 l 4.066921,10.845118 4.088269,-10.845118 H 73.49953 V 72.379166 H 71.396692 V 58.385121 L 67.287075,69.315634 H 65.120183 L 61.010567,58.385121 v 13.994045 h -2.092165 z m -16.246333,0 h 2.166892 v 9.681616 q 0,2.561839 0.928668,3.693318 0.928667,1.120804 3.010159,1.120804 2.070819,0 2.999486,-1.120804 0.928667,-1.131479 0.928667,-3.693318 v -9.681616 h 2.166886 v 9.948474 q 0,3.116904 -1.547776,4.70738 -1.537104,1.590474 -4.547263,1.590474 -3.020833,0 -4.568615,-1.590474 -1.537104,-1.590476 -1.537104,-4.70738 z m -16.192953,0 h 2.156213 v 6.532689 h 7.83496 v -6.532689 h 2.156213 v 15.936773 h -2.156213 v -7.589448 h -7.83496 v 7.589448 h -2.156213 z m -15.563168,0 h 13.481671 v 1.814636 H 18.740226 V 72.379166 H 16.573339 V 58.257029 H 10.915948 Z M 65.497127,39.809967 q -2.34835,0 -3.736011,1.750588 -1.376987,1.750588 -1.376987,4.771419 0,3.010157 1.376987,4.760745 1.387661,1.750588 3.736011,1.750588 2.348349,0 3.714662,-1.750588 1.376986,-1.750588 1.376986,-4.760745 0,-3.020831 -1.376986,-4.771419 -1.366313,-1.750588 -3.714662,-1.750588 z m 0,-1.750588 q 3.351735,0 5.358506,2.252281 2.006772,2.241606 2.006772,6.020314 0,3.768034 -2.006772,6.020315 -2.006771,2.241606 -5.358506,2.241606 -3.36241,0 -5.379856,-2.241606 -2.006771,-2.241607 -2.006771,-6.020315 0,-3.778708 2.006771,-6.020314 2.017446,-2.252281 5.379856,-2.252281 z m -22.821688,0.288206 h 2.903414 L 52.64525,51.679807 V 38.347585 h 2.092166 V 54.28434 H 51.834001 L 44.767605,40.952119 V 54.28434 h -2.092166 z" />
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

@ -54,7 +54,6 @@ span.linenos.special { color: #000000; background-color: #ffffc0; padding-left:
.highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #000000 } /* Name.Variable */
.highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */
.highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */
.highlight .w { color: #f8f8f8 } /* Text.Whitespace */
.highlight .mb { color: #0000cf; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */

@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>7. Collectors &amp; Extractors &#8212; MIPLearn 0.3</title>
<title>10. Collectors &amp; Extractors &#8212; MIPLearn 0.3</title>
<link href="../../_static/css/theme.css" rel="stylesheet" />
<link href="../../_static/css/index.c5995385ac14fb8791e8eb36b4908be2.css" rel="stylesheet" />
@ -36,8 +36,8 @@
<script src="../../_static/sphinx-book-theme.12a9622fbb08dcb3a2a40b2c02b83a57.js"></script>
<link rel="index" title="Index" href="../../genindex/" />
<link rel="search" title="Search" href="../../search/" />
<link rel="next" title="8. Components" href="../components/" />
<link rel="prev" title="6. Benchmark Problems" href="../problems/" />
<link rel="next" title="11. Components" href="../components/" />
<link rel="prev" title="9. Benchmark Problems" href="../problems/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="docsearch:language" content="en" />
@ -66,6 +66,28 @@
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
@ -73,59 +95,59 @@
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../guide/problems/">
1. Benchmark Problems
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/collectors/">
2. Training Data Collectors
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/features/">
3. Feature Extractors
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/primal/">
4. Primal Components
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/solvers/">
5. Solvers
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
API Reference
Python API Reference
</span>
</p>
<ul class="current nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../problems/">
6. Benchmark Problems
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1 current active">
<a class="current reference internal" href="#">
7. Collectors &amp; Extractors
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../components/">
8. Components
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../solvers/">
9. Solvers
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../helpers/">
10. Helpers
13. Helpers
</a>
</li>
</ul>
@ -197,27 +219,27 @@
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.classifiers.minprob">
7.1. miplearn.classifiers.minprob
10.1. miplearn.classifiers.minprob
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.classifiers.singleclass">
7.2. miplearn.classifiers.singleclass
10.2. miplearn.classifiers.singleclass
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.collectors.basic">
7.3. miplearn.collectors.basic
10.3. miplearn.collectors.basic
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#miplearn-features-fields">
7.4. miplearn.features.fields
<a class="reference internal nav-link" href="#module-miplearn.extractors.fields">
10.4. miplearn.extractors.fields
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#miplearn-features-alvlouweh2017">
7.5. miplearn.features.AlvLouWeh2017
<a class="reference internal nav-link" href="#module-miplearn.extractors.AlvLouWeh2017">
10.5. miplearn.extractors.AlvLouWeh2017
</a>
</li>
</ul>
@ -232,9 +254,9 @@
<div>
<div class="section" id="collectors-extractors">
<h1><span class="section-number">7. </span>Collectors &amp; Extractors<a class="headerlink" href="#collectors-extractors" title="Permalink to this headline"></a></h1>
<h1><span class="section-number">10. </span>Collectors &amp; Extractors<a class="headerlink" href="#collectors-extractors" title="Permalink to this headline"></a></h1>
<div class="section" id="module-miplearn.classifiers.minprob">
<span id="miplearn-classifiers-minprob"></span><h2><span class="section-number">7.1. </span>miplearn.classifiers.minprob<a class="headerlink" href="#module-miplearn.classifiers.minprob" title="Permalink to this headline"></a></h2>
<span id="miplearn-classifiers-minprob"></span><h2><span class="section-number">10.1. </span>miplearn.classifiers.minprob<a class="headerlink" href="#module-miplearn.classifiers.minprob" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.classifiers.minprob.MinProbabilityClassifier">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.classifiers.minprob.</span></code><code class="sig-name descname"><span class="pre">MinProbabilityClassifier</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="pre">base_clf:</span> <span class="pre">Any,</span> <span class="pre">thresholds:</span> <span class="pre">List[float],</span> <span class="pre">clone_fn:</span> <span class="pre">Callable[[Any],</span> <span class="pre">Any]</span> <span class="pre">=</span> <span class="pre">&lt;function</span> <span class="pre">clone&gt;</span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.classifiers.minprob.MinProbabilityClassifier" title="Permalink to this definition"></a></dt>
@ -258,7 +280,7 @@ the meta-classifier returns that prediction. Otherwise, it returns NaN.</p>
</div>
<div class="section" id="module-miplearn.classifiers.singleclass">
<span id="miplearn-classifiers-singleclass"></span><h2><span class="section-number">7.2. </span>miplearn.classifiers.singleclass<a class="headerlink" href="#module-miplearn.classifiers.singleclass" title="Permalink to this headline"></a></h2>
<span id="miplearn-classifiers-singleclass"></span><h2><span class="section-number">10.2. </span>miplearn.classifiers.singleclass<a class="headerlink" href="#module-miplearn.classifiers.singleclass" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.classifiers.singleclass.SingleClassFix">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.classifiers.singleclass.</span></code><code class="sig-name descname"><span class="pre">SingleClassFix</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="pre">base_clf:</span> <span class="pre">sklearn.base.BaseEstimator</span></em>, <em class="sig-param"><span class="pre">clone_fn:</span> <span class="pre">Callable</span> <span class="pre">=</span> <span class="pre">&lt;function</span> <span class="pre">clone&gt;</span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.classifiers.singleclass.SingleClassFix" title="Permalink to this definition"></a></dt>
@ -282,10 +304,10 @@ and returns its predictions instead.</p>
</div>
<div class="section" id="module-miplearn.collectors.basic">
<span id="miplearn-collectors-basic"></span><h2><span class="section-number">7.3. </span>miplearn.collectors.basic<a class="headerlink" href="#module-miplearn.collectors.basic" title="Permalink to this headline"></a></h2>
<span id="miplearn-collectors-basic"></span><h2><span class="section-number">10.3. </span>miplearn.collectors.basic<a class="headerlink" href="#module-miplearn.collectors.basic" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.collectors.basic.BasicCollector">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.collectors.basic.</span></code><code class="sig-name descname"><span class="pre">BasicCollector</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="o"><span class="pre">*</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">time_limit_sec</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">float</span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">inf</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.collectors.basic.BasicCollector" title="Permalink to this definition"></a></dt>
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.collectors.basic.</span></code><code class="sig-name descname"><span class="pre">BasicCollector</span></code><a class="headerlink" href="#miplearn.collectors.basic.BasicCollector" title="Permalink to this definition"></a></dt>
<dd><p>Bases: <code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></p>
<dl class="py method">
<dt id="miplearn.collectors.basic.BasicCollector.collect">
@ -295,11 +317,59 @@ and returns its predictions instead.</p>
</dd></dl>
</div>
<div class="section" id="miplearn-features-fields">
<h2><span class="section-number">7.4. </span>miplearn.features.fields<a class="headerlink" href="#miplearn-features-fields" title="Permalink to this headline"></a></h2>
<div class="section" id="module-miplearn.extractors.fields">
<span id="miplearn-extractors-fields"></span><h2><span class="section-number">10.4. </span>miplearn.extractors.fields<a class="headerlink" href="#module-miplearn.extractors.fields" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.extractors.fields.H5FieldsExtractor">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.extractors.fields.</span></code><code class="sig-name descname"><span class="pre">H5FieldsExtractor</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">instance_fields</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">List</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">]</span></span><span class="p"><span class="pre">]</span></span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">var_fields</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">List</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">]</span></span><span class="p"><span class="pre">]</span></span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">constr_fields</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">List</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">]</span></span><span class="p"><span class="pre">]</span></span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.extractors.fields.H5FieldsExtractor" title="Permalink to this definition"></a></dt>
<dd><p>Bases: <code class="xref py py-class docutils literal notranslate"><span class="pre">miplearn.extractors.abstract.FeaturesExtractor</span></code></p>
<dl class="py method">
<dt id="miplearn.extractors.fields.H5FieldsExtractor.get_constr_features">
<code class="sig-name descname"><span class="pre">get_constr_features</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">h5</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><a class="reference internal" href="../helpers/#miplearn.h5.H5File" title="miplearn.h5.H5File"><span class="pre">miplearn.h5.H5File</span></a></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">numpy.ndarray</span><a class="headerlink" href="#miplearn.extractors.fields.H5FieldsExtractor.get_constr_features" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
<dt id="miplearn.extractors.fields.H5FieldsExtractor.get_instance_features">
<code class="sig-name descname"><span class="pre">get_instance_features</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">h5</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><a class="reference internal" href="../helpers/#miplearn.h5.H5File" title="miplearn.h5.H5File"><span class="pre">miplearn.h5.H5File</span></a></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">numpy.ndarray</span><a class="headerlink" href="#miplearn.extractors.fields.H5FieldsExtractor.get_instance_features" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
<dt id="miplearn.extractors.fields.H5FieldsExtractor.get_var_features">
<code class="sig-name descname"><span class="pre">get_var_features</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">h5</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><a class="reference internal" href="../helpers/#miplearn.h5.H5File" title="miplearn.h5.H5File"><span class="pre">miplearn.h5.H5File</span></a></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">numpy.ndarray</span><a class="headerlink" href="#miplearn.extractors.fields.H5FieldsExtractor.get_var_features" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
</div>
<div class="section" id="miplearn-features-alvlouweh2017">
<h2><span class="section-number">7.5. </span>miplearn.features.AlvLouWeh2017<a class="headerlink" href="#miplearn-features-alvlouweh2017" title="Permalink to this headline"></a></h2>
<div class="section" id="module-miplearn.extractors.AlvLouWeh2017">
<span id="miplearn-extractors-alvlouweh2017"></span><h2><span class="section-number">10.5. </span>miplearn.extractors.AlvLouWeh2017<a class="headerlink" href="#module-miplearn.extractors.AlvLouWeh2017" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.extractors.AlvLouWeh2017.</span></code><code class="sig-name descname"><span class="pre">AlvLouWeh2017Extractor</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">with_m1</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">bool</span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">with_m2</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">bool</span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">with_m3</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">bool</span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">True</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor" title="Permalink to this definition"></a></dt>
<dd><p>Bases: <code class="xref py py-class docutils literal notranslate"><span class="pre">miplearn.extractors.abstract.FeaturesExtractor</span></code></p>
<dl class="py method">
<dt id="miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor.get_constr_features">
<code class="sig-name descname"><span class="pre">get_constr_features</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">h5</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><a class="reference internal" href="../helpers/#miplearn.h5.H5File" title="miplearn.h5.H5File"><span class="pre">miplearn.h5.H5File</span></a></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">numpy.ndarray</span><a class="headerlink" href="#miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor.get_constr_features" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
<dt id="miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor.get_instance_features">
<code class="sig-name descname"><span class="pre">get_instance_features</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">h5</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><a class="reference internal" href="../helpers/#miplearn.h5.H5File" title="miplearn.h5.H5File"><span class="pre">miplearn.h5.H5File</span></a></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">numpy.ndarray</span><a class="headerlink" href="#miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor.get_instance_features" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
<dt id="miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor.get_var_features">
<code class="sig-name descname"><span class="pre">get_var_features</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">h5</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><a class="reference internal" href="../helpers/#miplearn.h5.H5File" title="miplearn.h5.H5File"><span class="pre">miplearn.h5.H5File</span></a></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">numpy.ndarray</span><a class="headerlink" href="#miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor.get_var_features" title="Permalink to this definition"></a></dt>
<dd><dl class="simple">
<dt>Computes static variable features described in:</dt><dd><p>Alvarez, A. M., Louveaux, Q., &amp; Wehenkel, L. (2017). A machine learning-based
approximation of strong branching. INFORMS Journal on Computing, 29(1),
185-195.</p>
</dd>
</dl>
</dd></dl>
</dd></dl>
</div>
</div>
@ -309,8 +379,8 @@ and returns its predictions instead.</p>
<div class='prev-next-bottom'>
<a class='left-prev' id="prev-link" href="../problems/" title="previous page"><span class="section-number">6. </span>Benchmark Problems</a>
<a class='right-next' id="next-link" href="../components/" title="next page"><span class="section-number">8. </span>Components</a>
<a class='left-prev' id="prev-link" href="../problems/" title="previous page"><span class="section-number">9. </span>Benchmark Problems</a>
<a class='right-next' id="next-link" href="../components/" title="next page"><span class="section-number">11. </span>Components</a>
</div>
@ -320,7 +390,7 @@ and returns its predictions instead.</p>
<div class="container">
<p>
&copy; Copyright 2020-2022, UChicago Argonne, LLC.<br/>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>

@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>8. Components &#8212; MIPLearn 0.3</title>
<title>11. Components &#8212; MIPLearn 0.3</title>
<link href="../../_static/css/theme.css" rel="stylesheet" />
<link href="../../_static/css/index.c5995385ac14fb8791e8eb36b4908be2.css" rel="stylesheet" />
@ -36,8 +36,8 @@
<script src="../../_static/sphinx-book-theme.12a9622fbb08dcb3a2a40b2c02b83a57.js"></script>
<link rel="index" title="Index" href="../../genindex/" />
<link rel="search" title="Search" href="../../search/" />
<link rel="next" title="9. Solvers" href="../solvers/" />
<link rel="prev" title="7. Collectors &amp; Extractors" href="../collectors/" />
<link rel="next" title="12. Solvers" href="../solvers/" />
<link rel="prev" title="10. Collectors &amp; Extractors" href="../collectors/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="docsearch:language" content="en" />
@ -66,6 +66,28 @@
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
@ -73,59 +95,59 @@
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../guide/problems/">
1. Benchmark Problems
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/collectors/">
2. Training Data Collectors
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/features/">
3. Feature Extractors
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/primal/">
4. Primal Components
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/solvers/">
5. Solvers
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
API Reference
Python API Reference
</span>
</p>
<ul class="current nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../problems/">
6. Benchmark Problems
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../collectors/">
7. Collectors &amp; Extractors
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1 current active">
<a class="current reference internal" href="#">
8. Components
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../solvers/">
9. Solvers
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../helpers/">
10. Helpers
13. Helpers
</a>
</li>
</ul>
@ -197,27 +219,27 @@
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.components.primal.actions">
8.1. miplearn.components.primal.actions
11.1. miplearn.components.primal.actions
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.components.primal.expert">
8.2. miplearn.components.primal.expert
11.2. miplearn.components.primal.expert
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.components.primal.indep">
8.3. miplearn.components.primal.indep
11.3. miplearn.components.primal.indep
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.components.primal.joint">
8.4. miplearn.components.primal.joint
11.4. miplearn.components.primal.joint
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.components.primal.mem">
8.5. miplearn.components.primal.mem
11.5. miplearn.components.primal.mem
</a>
</li>
</ul>
@ -232,9 +254,9 @@
<div>
<div class="section" id="components">
<h1><span class="section-number">8. </span>Components<a class="headerlink" href="#components" title="Permalink to this headline"></a></h1>
<h1><span class="section-number">11. </span>Components<a class="headerlink" href="#components" title="Permalink to this headline"></a></h1>
<div class="section" id="module-miplearn.components.primal.actions">
<span id="miplearn-components-primal-actions"></span><h2><span class="section-number">8.1. </span>miplearn.components.primal.actions<a class="headerlink" href="#module-miplearn.components.primal.actions" title="Permalink to this headline"></a></h2>
<span id="miplearn-components-primal-actions"></span><h2><span class="section-number">11.1. </span>miplearn.components.primal.actions<a class="headerlink" href="#module-miplearn.components.primal.actions" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.components.primal.actions.EnforceProximity">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.components.primal.actions.</span></code><code class="sig-name descname"><span class="pre">EnforceProximity</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">tol</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">float</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.components.primal.actions.EnforceProximity" title="Permalink to this definition"></a></dt>
@ -281,7 +303,7 @@
</div>
<div class="section" id="module-miplearn.components.primal.expert">
<span id="miplearn-components-primal-expert"></span><h2><span class="section-number">8.2. </span>miplearn.components.primal.expert<a class="headerlink" href="#module-miplearn.components.primal.expert" title="Permalink to this headline"></a></h2>
<span id="miplearn-components-primal-expert"></span><h2><span class="section-number">11.2. </span>miplearn.components.primal.expert<a class="headerlink" href="#module-miplearn.components.primal.expert" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.components.primal.expert.ExpertPrimalComponent">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.components.primal.expert.</span></code><code class="sig-name descname"><span class="pre">ExpertPrimalComponent</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">action</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><a class="reference internal" href="#miplearn.components.primal.actions.PrimalComponentAction" title="miplearn.components.primal.actions.PrimalComponentAction"><span class="pre">miplearn.components.primal.actions.PrimalComponentAction</span></a></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.components.primal.expert.ExpertPrimalComponent" title="Permalink to this definition"></a></dt>
@ -300,7 +322,7 @@
</div>
<div class="section" id="module-miplearn.components.primal.indep">
<span id="miplearn-components-primal-indep"></span><h2><span class="section-number">8.3. </span>miplearn.components.primal.indep<a class="headerlink" href="#module-miplearn.components.primal.indep" title="Permalink to this headline"></a></h2>
<span id="miplearn-components-primal-indep"></span><h2><span class="section-number">11.3. </span>miplearn.components.primal.indep<a class="headerlink" href="#module-miplearn.components.primal.indep" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.components.primal.indep.IndependentVarsPrimalComponent">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.components.primal.indep.</span></code><code class="sig-name descname"><span class="pre">IndependentVarsPrimalComponent</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="pre">base_clf:</span> <span class="pre">Any,</span> <span class="pre">extractor:</span> <span class="pre">miplearn.extractors.abstract.FeaturesExtractor,</span> <span class="pre">action:</span> <span class="pre">miplearn.components.primal.actions.PrimalComponentAction,</span> <span class="pre">clone_fn:</span> <span class="pre">Callable[[Any],</span> <span class="pre">Any]</span> <span class="pre">=</span> <span class="pre">&lt;function</span> <span class="pre">clone&gt;</span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.components.primal.indep.IndependentVarsPrimalComponent" title="Permalink to this definition"></a></dt>
@ -319,7 +341,7 @@
</div>
<div class="section" id="module-miplearn.components.primal.joint">
<span id="miplearn-components-primal-joint"></span><h2><span class="section-number">8.4. </span>miplearn.components.primal.joint<a class="headerlink" href="#module-miplearn.components.primal.joint" title="Permalink to this headline"></a></h2>
<span id="miplearn-components-primal-joint"></span><h2><span class="section-number">11.4. </span>miplearn.components.primal.joint<a class="headerlink" href="#module-miplearn.components.primal.joint" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.components.primal.joint.JointVarsPrimalComponent">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.components.primal.joint.</span></code><code class="sig-name descname"><span class="pre">JointVarsPrimalComponent</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">clf</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">Any</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">extractor</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">miplearn.extractors.abstract.FeaturesExtractor</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">action</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><a class="reference internal" href="#miplearn.components.primal.actions.PrimalComponentAction" title="miplearn.components.primal.actions.PrimalComponentAction"><span class="pre">miplearn.components.primal.actions.PrimalComponentAction</span></a></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.components.primal.joint.JointVarsPrimalComponent" title="Permalink to this definition"></a></dt>
@ -338,7 +360,7 @@
</div>
<div class="section" id="module-miplearn.components.primal.mem">
<span id="miplearn-components-primal-mem"></span><h2><span class="section-number">8.5. </span>miplearn.components.primal.mem<a class="headerlink" href="#module-miplearn.components.primal.mem" title="Permalink to this headline"></a></h2>
<span id="miplearn-components-primal-mem"></span><h2><span class="section-number">11.5. </span>miplearn.components.primal.mem<a class="headerlink" href="#module-miplearn.components.primal.mem" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.components.primal.mem.MemorizingPrimalComponent">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.components.primal.mem.</span></code><code class="sig-name descname"><span class="pre">MemorizingPrimalComponent</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">clf</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">Any</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">extractor</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">miplearn.extractors.abstract.FeaturesExtractor</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">constructor</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><a class="reference internal" href="#miplearn.components.primal.mem.SolutionConstructor" title="miplearn.components.primal.mem.SolutionConstructor"><span class="pre">miplearn.components.primal.mem.SolutionConstructor</span></a></span></em>, <em class="sig-param"><span class="n"><span class="pre">action</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><a class="reference internal" href="#miplearn.components.primal.actions.PrimalComponentAction" title="miplearn.components.primal.actions.PrimalComponentAction"><span class="pre">miplearn.components.primal.actions.PrimalComponentAction</span></a></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.components.primal.mem.MemorizingPrimalComponent" title="Permalink to this definition"></a></dt>
@ -408,8 +430,8 @@ thresholds[0]; (ii) sets the variable to one if the mean is above thresholds[1];
<div class='prev-next-bottom'>
<a class='left-prev' id="prev-link" href="../collectors/" title="previous page"><span class="section-number">7. </span>Collectors &amp; Extractors</a>
<a class='right-next' id="next-link" href="../solvers/" title="next page"><span class="section-number">9. </span>Solvers</a>
<a class='left-prev' id="prev-link" href="../collectors/" title="previous page"><span class="section-number">10. </span>Collectors &amp; Extractors</a>
<a class='right-next' id="next-link" href="../solvers/" title="next page"><span class="section-number">12. </span>Solvers</a>
</div>
@ -419,7 +441,7 @@ thresholds[0]; (ii) sets the variable to one if the mean is above thresholds[1];
<div class="container">
<p>
&copy; Copyright 2020-2022, UChicago Argonne, LLC.<br/>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>

@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>10. Helpers &#8212; MIPLearn 0.3</title>
<title>13. Helpers &#8212; MIPLearn 0.3</title>
<link href="../../_static/css/theme.css" rel="stylesheet" />
<link href="../../_static/css/index.c5995385ac14fb8791e8eb36b4908be2.css" rel="stylesheet" />
@ -36,7 +36,7 @@
<script src="../../_static/sphinx-book-theme.12a9622fbb08dcb3a2a40b2c02b83a57.js"></script>
<link rel="index" title="Index" href="../../genindex/" />
<link rel="search" title="Search" href="../../search/" />
<link rel="prev" title="9. Solvers" href="../solvers/" />
<link rel="prev" title="12. Solvers" href="../solvers/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="docsearch:language" content="en" />
@ -65,6 +65,28 @@
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
@ -72,59 +94,59 @@
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../guide/problems/">
1. Benchmark Problems
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/collectors/">
2. Training Data Collectors
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/features/">
3. Feature Extractors
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/primal/">
4. Primal Components
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/solvers/">
5. Solvers
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
API Reference
Python API Reference
</span>
</p>
<ul class="current nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../problems/">
6. Benchmark Problems
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../collectors/">
7. Collectors &amp; Extractors
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../components/">
8. Components
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../solvers/">
9. Solvers
12. Solvers
</a>
</li>
<li class="toctree-l1 current active">
<a class="current reference internal" href="#">
10. Helpers
13. Helpers
</a>
</li>
</ul>
@ -196,12 +218,12 @@
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.io">
10.1. miplearn.io
13.1. miplearn.io
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.h5">
10.2. miplearn.h5
13.2. miplearn.h5
</a>
</li>
</ul>
@ -216,26 +238,36 @@
<div>
<div class="section" id="helpers">
<h1><span class="section-number">10. </span>Helpers<a class="headerlink" href="#helpers" title="Permalink to this headline"></a></h1>
<h1><span class="section-number">13. </span>Helpers<a class="headerlink" href="#helpers" title="Permalink to this headline"></a></h1>
<div class="section" id="module-miplearn.io">
<span id="miplearn-io"></span><h2><span class="section-number">10.1. </span>miplearn.io<a class="headerlink" href="#module-miplearn.io" title="Permalink to this headline"></a></h2>
<span id="miplearn-io"></span><h2><span class="section-number">13.1. </span>miplearn.io<a class="headerlink" href="#module-miplearn.io" title="Permalink to this headline"></a></h2>
<dl class="py function">
<dt id="miplearn.io.gzip">
<code class="sig-prename descclassname"><span class="pre">miplearn.io.</span></code><code class="sig-name descname"><span class="pre">gzip</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">filename</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">None</span><a class="headerlink" href="#miplearn.io.gzip" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py function">
<dt id="miplearn.io.load">
<code class="sig-prename descclassname"><span class="pre">miplearn.io.</span></code><code class="sig-name descname"><span class="pre">load</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">filename</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">build_model</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">Callable</span></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">Any</span><a class="headerlink" href="#miplearn.io.load" title="Permalink to this definition"></a></dt>
<dt id="miplearn.io.read_pkl_gz">
<code class="sig-prename descclassname"><span class="pre">miplearn.io.</span></code><code class="sig-name descname"><span class="pre">read_pkl_gz</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">filename</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">Any</span><a class="headerlink" href="#miplearn.io.read_pkl_gz" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py function">
<dt id="miplearn.io.save">
<code class="sig-prename descclassname"><span class="pre">miplearn.io.</span></code><code class="sig-name descname"><span class="pre">save</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">objs</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">List</span><span class="p"><span class="pre">[</span></span><span class="pre">Any</span><span class="p"><span class="pre">]</span></span></span></em>, <em class="sig-param"><span class="n"><span class="pre">dirname</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">prefix</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">str</span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">''</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">n_jobs</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">int</span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">1</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">progress</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">bool</span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">List</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">]</span></span><a class="headerlink" href="#miplearn.io.save" title="Permalink to this definition"></a></dt>
<dt id="miplearn.io.write_pkl_gz">
<code class="sig-prename descclassname"><span class="pre">miplearn.io.</span></code><code class="sig-name descname"><span class="pre">write_pkl_gz</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">objs</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">List</span><span class="p"><span class="pre">[</span></span><span class="pre">Any</span><span class="p"><span class="pre">]</span></span></span></em>, <em class="sig-param"><span class="n"><span class="pre">dirname</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">prefix</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">str</span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">''</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">n_jobs</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">int</span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">1</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">progress</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">bool</span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">List</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">]</span></span><a class="headerlink" href="#miplearn.io.write_pkl_gz" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</div>
<div class="section" id="module-miplearn.h5">
<span id="miplearn-h5"></span><h2><span class="section-number">10.2. </span>miplearn.h5<a class="headerlink" href="#module-miplearn.h5" title="Permalink to this headline"></a></h2>
<span id="miplearn-h5"></span><h2><span class="section-number">13.2. </span>miplearn.h5<a class="headerlink" href="#module-miplearn.h5" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.h5.H5File">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.h5.</span></code><code class="sig-name descname"><span class="pre">H5File</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">filename</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">mode</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">str</span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">'r+'</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.h5.H5File" title="Permalink to this definition"></a></dt>
<dd><p>Bases: <code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></p>
<dl class="py method">
<dt id="miplearn.h5.H5File.close">
<code class="sig-name descname"><span class="pre">close</span></code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.h5.H5File.close" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
<dt id="miplearn.h5.H5File.get_array">
<code class="sig-name descname"><span class="pre">get_array</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">numpy.ndarray</span><span class="p"><span class="pre">]</span></span><a class="headerlink" href="#miplearn.h5.H5File.get_array" title="Permalink to this definition"></a></dt>
@ -253,7 +285,7 @@
<dl class="py method">
<dt id="miplearn.h5.H5File.get_sparse">
<code class="sig-name descname"><span class="pre">get_sparse</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">scipy.sparse._coo.coo_matrix</span><span class="p"><span class="pre">]</span></span><a class="headerlink" href="#miplearn.h5.H5File.get_sparse" title="Permalink to this definition"></a></dt>
<code class="sig-name descname"><span class="pre">get_sparse</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">scipy.sparse.coo.coo_matrix</span><span class="p"><span class="pre">]</span></span><a class="headerlink" href="#miplearn.h5.H5File.get_sparse" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
@ -273,7 +305,7 @@
<dl class="py method">
<dt id="miplearn.h5.H5File.put_sparse">
<code class="sig-name descname"><span class="pre">put_sparse</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">value</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">scipy.sparse._coo.coo_matrix</span></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">None</span><a class="headerlink" href="#miplearn.h5.H5File.put_sparse" title="Permalink to this definition"></a></dt>
<code class="sig-name descname"><span class="pre">put_sparse</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">value</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">scipy.sparse.coo.coo_matrix</span></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">None</span><a class="headerlink" href="#miplearn.h5.H5File.put_sparse" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -287,7 +319,7 @@
<div class='prev-next-bottom'>
<a class='left-prev' id="prev-link" href="../solvers/" title="previous page"><span class="section-number">9. </span>Solvers</a>
<a class='left-prev' id="prev-link" href="../solvers/" title="previous page"><span class="section-number">12. </span>Solvers</a>
</div>
@ -297,7 +329,7 @@
<div class="container">
<p>
&copy; Copyright 2020-2022, UChicago Argonne, LLC.<br/>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>

@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>6. Benchmark Problems &#8212; MIPLearn 0.3</title>
<title>9. Benchmark Problems &#8212; MIPLearn 0.3</title>
<link href="../../_static/css/theme.css" rel="stylesheet" />
<link href="../../_static/css/index.c5995385ac14fb8791e8eb36b4908be2.css" rel="stylesheet" />
@ -36,8 +36,8 @@
<script src="../../_static/sphinx-book-theme.12a9622fbb08dcb3a2a40b2c02b83a57.js"></script>
<link rel="index" title="Index" href="../../genindex/" />
<link rel="search" title="Search" href="../../search/" />
<link rel="next" title="7. Collectors &amp; Extractors" href="../collectors/" />
<link rel="prev" title="5. Solvers" href="../../guide/solvers/" />
<link rel="next" title="10. Collectors &amp; Extractors" href="../collectors/" />
<link rel="prev" title="8. Solvers" href="../../guide/solvers/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="docsearch:language" content="en" />
@ -66,6 +66,28 @@
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
@ -73,59 +95,59 @@
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../guide/problems/">
1. Benchmark Problems
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/collectors/">
2. Training Data Collectors
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/features/">
3. Feature Extractors
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/primal/">
4. Primal Components
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/solvers/">
5. Solvers
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
API Reference
Python API Reference
</span>
</p>
<ul class="current nav bd-sidenav">
<li class="toctree-l1 current active">
<a class="current reference internal" href="#">
6. Benchmark Problems
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../collectors/">
7. Collectors &amp; Extractors
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../components/">
8. Components
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../solvers/">
9. Solvers
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../helpers/">
10. Helpers
13. Helpers
</a>
</li>
</ul>
@ -197,47 +219,47 @@
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.problems.binpack">
6.1. miplearn.problems.binpack
9.1. miplearn.problems.binpack
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.problems.multiknapsack">
6.2. miplearn.problems.multiknapsack
9.2. miplearn.problems.multiknapsack
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.problems.pmedian">
6.3. miplearn.problems.pmedian
9.3. miplearn.problems.pmedian
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.problems.setcover">
6.4. miplearn.problems.setcover
9.4. miplearn.problems.setcover
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.problems.setpack">
6.5. miplearn.problems.setpack
9.5. miplearn.problems.setpack
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.problems.stab">
6.6. miplearn.problems.stab
9.6. miplearn.problems.stab
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.problems.tsp">
6.7. miplearn.problems.tsp
9.7. miplearn.problems.tsp
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.problems.uc">
6.8. miplearn.problems.uc
9.8. miplearn.problems.uc
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.problems.vertexcover">
6.9. miplearn.problems.vertexcover
9.9. miplearn.problems.vertexcover
</a>
</li>
</ul>
@ -252,9 +274,9 @@
<div>
<div class="section" id="benchmark-problems">
<h1><span class="section-number">6. </span>Benchmark Problems<a class="headerlink" href="#benchmark-problems" title="Permalink to this headline"></a></h1>
<h1><span class="section-number">9. </span>Benchmark Problems<a class="headerlink" href="#benchmark-problems" title="Permalink to this headline"></a></h1>
<div class="section" id="module-miplearn.problems.binpack">
<span id="miplearn-problems-binpack"></span><h2><span class="section-number">6.1. </span>miplearn.problems.binpack<a class="headerlink" href="#module-miplearn.problems.binpack" title="Permalink to this headline"></a></h2>
<span id="miplearn-problems-binpack"></span><h2><span class="section-number">9.1. </span>miplearn.problems.binpack<a class="headerlink" href="#module-miplearn.problems.binpack" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.problems.binpack.BinPackData">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.problems.binpack.</span></code><code class="sig-name descname"><span class="pre">BinPackData</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">sizes</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">capacity</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">int</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.problems.binpack.BinPackData" title="Permalink to this definition"></a></dt>
@ -312,13 +334,13 @@ If <cite>False</cite>, generates completely different instances.</p></li>
<dl class="py function">
<dt id="miplearn.problems.binpack.build_binpack_model">
<code class="sig-prename descclassname"><span class="pre">miplearn.problems.binpack.</span></code><code class="sig-name descname"><span class="pre">build_binpack_model</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><a class="reference internal" href="#miplearn.problems.binpack.BinPackData" title="miplearn.problems.binpack.BinPackData"><span class="pre">miplearn.problems.binpack.BinPackData</span></a></span></em><span class="sig-paren">)</span> &#x2192; <a class="reference internal" href="../solvers/#miplearn.solvers.gurobi.GurobiModel" title="miplearn.solvers.gurobi.GurobiModel"><span class="pre">miplearn.solvers.gurobi.GurobiModel</span></a><a class="headerlink" href="#miplearn.problems.binpack.build_binpack_model" title="Permalink to this definition"></a></dt>
<code class="sig-prename descclassname"><span class="pre">miplearn.problems.binpack.</span></code><code class="sig-name descname"><span class="pre">build_binpack_model</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">Union</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">,</span> </span><a class="reference internal" href="#miplearn.problems.binpack.BinPackData" title="miplearn.problems.binpack.BinPackData"><span class="pre">miplearn.problems.binpack.BinPackData</span></a><span class="p"><span class="pre">]</span></span></span></em><span class="sig-paren">)</span> &#x2192; <a class="reference internal" href="../solvers/#miplearn.solvers.gurobi.GurobiModel" title="miplearn.solvers.gurobi.GurobiModel"><span class="pre">miplearn.solvers.gurobi.GurobiModel</span></a><a class="headerlink" href="#miplearn.problems.binpack.build_binpack_model" title="Permalink to this definition"></a></dt>
<dd><p>Converts bin packing problem data into a concrete Gurobipy model.</p>
</dd></dl>
</div>
<div class="section" id="module-miplearn.problems.multiknapsack">
<span id="miplearn-problems-multiknapsack"></span><h2><span class="section-number">6.2. </span>miplearn.problems.multiknapsack<a class="headerlink" href="#module-miplearn.problems.multiknapsack" title="Permalink to this headline"></a></h2>
<span id="miplearn-problems-multiknapsack"></span><h2><span class="section-number">9.2. </span>miplearn.problems.multiknapsack<a class="headerlink" href="#module-miplearn.problems.multiknapsack" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.problems.multiknapsack.MultiKnapsackData">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.problems.multiknapsack.</span></code><code class="sig-name descname"><span class="pre">MultiKnapsackData</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">prices</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">capacities</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">weights</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.problems.multiknapsack.MultiKnapsackData" title="Permalink to this definition"></a></dt>
@ -385,13 +407,13 @@ integer.</p></li>
<dl class="py function">
<dt id="miplearn.problems.multiknapsack.build_multiknapsack_model">
<code class="sig-prename descclassname"><span class="pre">miplearn.problems.multiknapsack.</span></code><code class="sig-name descname"><span class="pre">build_multiknapsack_model</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><a class="reference internal" href="#miplearn.problems.multiknapsack.MultiKnapsackData" title="miplearn.problems.multiknapsack.MultiKnapsackData"><span class="pre">miplearn.problems.multiknapsack.MultiKnapsackData</span></a></span></em><span class="sig-paren">)</span> &#x2192; <a class="reference internal" href="../solvers/#miplearn.solvers.gurobi.GurobiModel" title="miplearn.solvers.gurobi.GurobiModel"><span class="pre">miplearn.solvers.gurobi.GurobiModel</span></a><a class="headerlink" href="#miplearn.problems.multiknapsack.build_multiknapsack_model" title="Permalink to this definition"></a></dt>
<code class="sig-prename descclassname"><span class="pre">miplearn.problems.multiknapsack.</span></code><code class="sig-name descname"><span class="pre">build_multiknapsack_model</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">Union</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">,</span> </span><a class="reference internal" href="#miplearn.problems.multiknapsack.MultiKnapsackData" title="miplearn.problems.multiknapsack.MultiKnapsackData"><span class="pre">miplearn.problems.multiknapsack.MultiKnapsackData</span></a><span class="p"><span class="pre">]</span></span></span></em><span class="sig-paren">)</span> &#x2192; <a class="reference internal" href="../solvers/#miplearn.solvers.gurobi.GurobiModel" title="miplearn.solvers.gurobi.GurobiModel"><span class="pre">miplearn.solvers.gurobi.GurobiModel</span></a><a class="headerlink" href="#miplearn.problems.multiknapsack.build_multiknapsack_model" title="Permalink to this definition"></a></dt>
<dd><p>Converts multi-knapsack problem data into a concrete Gurobipy model.</p>
</dd></dl>
</div>
<div class="section" id="module-miplearn.problems.pmedian">
<span id="miplearn-problems-pmedian"></span><h2><span class="section-number">6.3. </span>miplearn.problems.pmedian<a class="headerlink" href="#module-miplearn.problems.pmedian" title="Permalink to this headline"></a></h2>
<span id="miplearn-problems-pmedian"></span><h2><span class="section-number">9.3. </span>miplearn.problems.pmedian<a class="headerlink" href="#module-miplearn.problems.pmedian" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.problems.pmedian.PMedianData">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.problems.pmedian.</span></code><code class="sig-name descname"><span class="pre">PMedianData</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">distances</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">demands</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">p</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">capacities</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.problems.pmedian.PMedianData" title="Permalink to this definition"></a></dt>
@ -447,13 +469,13 @@ different demands, capacities and distances.</p>
<dl class="py function">
<dt id="miplearn.problems.pmedian.build_pmedian_model">
<code class="sig-prename descclassname"><span class="pre">miplearn.problems.pmedian.</span></code><code class="sig-name descname"><span class="pre">build_pmedian_model</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><a class="reference internal" href="#miplearn.problems.pmedian.PMedianData" title="miplearn.problems.pmedian.PMedianData"><span class="pre">miplearn.problems.pmedian.PMedianData</span></a></span></em><span class="sig-paren">)</span> &#x2192; <a class="reference internal" href="../solvers/#miplearn.solvers.gurobi.GurobiModel" title="miplearn.solvers.gurobi.GurobiModel"><span class="pre">miplearn.solvers.gurobi.GurobiModel</span></a><a class="headerlink" href="#miplearn.problems.pmedian.build_pmedian_model" title="Permalink to this definition"></a></dt>
<code class="sig-prename descclassname"><span class="pre">miplearn.problems.pmedian.</span></code><code class="sig-name descname"><span class="pre">build_pmedian_model</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">Union</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">,</span> </span><a class="reference internal" href="#miplearn.problems.pmedian.PMedianData" title="miplearn.problems.pmedian.PMedianData"><span class="pre">miplearn.problems.pmedian.PMedianData</span></a><span class="p"><span class="pre">]</span></span></span></em><span class="sig-paren">)</span> &#x2192; <a class="reference internal" href="../solvers/#miplearn.solvers.gurobi.GurobiModel" title="miplearn.solvers.gurobi.GurobiModel"><span class="pre">miplearn.solvers.gurobi.GurobiModel</span></a><a class="headerlink" href="#miplearn.problems.pmedian.build_pmedian_model" title="Permalink to this definition"></a></dt>
<dd><p>Converts capacitated p-median data into a concrete Gurobipy model.</p>
</dd></dl>
</div>
<div class="section" id="module-miplearn.problems.setcover">
<span id="miplearn-problems-setcover"></span><h2><span class="section-number">6.4. </span>miplearn.problems.setcover<a class="headerlink" href="#module-miplearn.problems.setcover" title="Permalink to this headline"></a></h2>
<span id="miplearn-problems-setcover"></span><h2><span class="section-number">9.4. </span>miplearn.problems.setcover<a class="headerlink" href="#module-miplearn.problems.setcover" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.problems.setcover.SetCoverData">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.problems.setcover.</span></code><code class="sig-name descname"><span class="pre">SetCoverData</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">costs</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">incidence_matrix</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.problems.setcover.SetCoverData" title="Permalink to this definition"></a></dt>
@ -461,7 +483,7 @@ different demands, capacities and distances.</p>
</div>
<div class="section" id="module-miplearn.problems.setpack">
<span id="miplearn-problems-setpack"></span><h2><span class="section-number">6.5. </span>miplearn.problems.setpack<a class="headerlink" href="#module-miplearn.problems.setpack" title="Permalink to this headline"></a></h2>
<span id="miplearn-problems-setpack"></span><h2><span class="section-number">9.5. </span>miplearn.problems.setpack<a class="headerlink" href="#module-miplearn.problems.setpack" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.problems.setpack.SetPackData">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.problems.setpack.</span></code><code class="sig-name descname"><span class="pre">SetPackData</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">costs</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">incidence_matrix</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.problems.setpack.SetPackData" title="Permalink to this definition"></a></dt>
@ -469,7 +491,7 @@ different demands, capacities and distances.</p>
</div>
<div class="section" id="module-miplearn.problems.stab">
<span id="miplearn-problems-stab"></span><h2><span class="section-number">6.6. </span>miplearn.problems.stab<a class="headerlink" href="#module-miplearn.problems.stab" title="Permalink to this headline"></a></h2>
<span id="miplearn-problems-stab"></span><h2><span class="section-number">9.6. </span>miplearn.problems.stab<a class="headerlink" href="#module-miplearn.problems.stab" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.problems.stab.MaxWeightStableSetData">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.problems.stab.</span></code><code class="sig-name descname"><span class="pre">MaxWeightStableSetData</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">graph</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">networkx.classes.graph.Graph</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">weights</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.problems.stab.MaxWeightStableSetData" title="Permalink to this definition"></a></dt>
@ -490,7 +512,7 @@ remaining parameters are sampled in the same way.</p>
</div>
<div class="section" id="module-miplearn.problems.tsp">
<span id="miplearn-problems-tsp"></span><h2><span class="section-number">6.7. </span>miplearn.problems.tsp<a class="headerlink" href="#module-miplearn.problems.tsp" title="Permalink to this headline"></a></h2>
<span id="miplearn-problems-tsp"></span><h2><span class="section-number">9.7. </span>miplearn.problems.tsp<a class="headerlink" href="#module-miplearn.problems.tsp" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.problems.tsp.TravelingSalesmanData">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.problems.tsp.</span></code><code class="sig-name descname"><span class="pre">TravelingSalesmanData</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">n_cities</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">distances</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.problems.tsp.TravelingSalesmanData" title="Permalink to this definition"></a></dt>
@ -504,7 +526,7 @@ remaining parameters are sampled in the same way.</p>
</div>
<div class="section" id="module-miplearn.problems.uc">
<span id="miplearn-problems-uc"></span><h2><span class="section-number">6.8. </span>miplearn.problems.uc<a class="headerlink" href="#module-miplearn.problems.uc" title="Permalink to this headline"></a></h2>
<span id="miplearn-problems-uc"></span><h2><span class="section-number">9.8. </span>miplearn.problems.uc<a class="headerlink" href="#module-miplearn.problems.uc" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.problems.uc.UnitCommitmentData">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.problems.uc.</span></code><code class="sig-name descname"><span class="pre">UnitCommitmentData</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">demand</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">min_power</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">max_power</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">min_uptime</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">min_downtime</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">cost_startup</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">cost_prod</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">cost_fixed</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.problems.uc.UnitCommitmentData" title="Permalink to this definition"></a></dt>
@ -512,7 +534,7 @@ remaining parameters are sampled in the same way.</p>
<dl class="py function">
<dt id="miplearn.problems.uc.build_uc_model">
<code class="sig-prename descclassname"><span class="pre">miplearn.problems.uc.</span></code><code class="sig-name descname"><span class="pre">build_uc_model</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><a class="reference internal" href="#miplearn.problems.uc.UnitCommitmentData" title="miplearn.problems.uc.UnitCommitmentData"><span class="pre">miplearn.problems.uc.UnitCommitmentData</span></a></span></em><span class="sig-paren">)</span> &#x2192; <a class="reference internal" href="../solvers/#miplearn.solvers.gurobi.GurobiModel" title="miplearn.solvers.gurobi.GurobiModel"><span class="pre">miplearn.solvers.gurobi.GurobiModel</span></a><a class="headerlink" href="#miplearn.problems.uc.build_uc_model" title="Permalink to this definition"></a></dt>
<code class="sig-prename descclassname"><span class="pre">miplearn.problems.uc.</span></code><code class="sig-name descname"><span class="pre">build_uc_model</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">Union</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">,</span> </span><a class="reference internal" href="#miplearn.problems.uc.UnitCommitmentData" title="miplearn.problems.uc.UnitCommitmentData"><span class="pre">miplearn.problems.uc.UnitCommitmentData</span></a><span class="p"><span class="pre">]</span></span></span></em><span class="sig-paren">)</span> &#x2192; <a class="reference internal" href="../solvers/#miplearn.solvers.gurobi.GurobiModel" title="miplearn.solvers.gurobi.GurobiModel"><span class="pre">miplearn.solvers.gurobi.GurobiModel</span></a><a class="headerlink" href="#miplearn.problems.uc.build_uc_model" title="Permalink to this definition"></a></dt>
<dd><p>Models the unit commitment problem according to equations (1)-(5) of:</p>
<blockquote>
<div><p>Bendotti, P., Fouilhoux, P. &amp; Rottner, C. The min-up/min-down unit
@ -523,7 +545,7 @@ commitment polytope. J Comb Optim 36, 1024-1058 (2018).
</div>
<div class="section" id="module-miplearn.problems.vertexcover">
<span id="miplearn-problems-vertexcover"></span><h2><span class="section-number">6.9. </span>miplearn.problems.vertexcover<a class="headerlink" href="#module-miplearn.problems.vertexcover" title="Permalink to this headline"></a></h2>
<span id="miplearn-problems-vertexcover"></span><h2><span class="section-number">9.9. </span>miplearn.problems.vertexcover<a class="headerlink" href="#module-miplearn.problems.vertexcover" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.problems.vertexcover.MinWeightVertexCoverData">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.problems.vertexcover.</span></code><code class="sig-name descname"><span class="pre">MinWeightVertexCoverData</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">graph</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">networkx.classes.graph.Graph</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">weights</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.problems.vertexcover.MinWeightVertexCoverData" title="Permalink to this definition"></a></dt>
@ -538,8 +560,8 @@ commitment polytope. J Comb Optim 36, 1024-1058 (2018).
<div class='prev-next-bottom'>
<a class='left-prev' id="prev-link" href="../../guide/solvers/" title="previous page"><span class="section-number">5. </span>Solvers</a>
<a class='right-next' id="next-link" href="../collectors/" title="next page"><span class="section-number">7. </span>Collectors &amp; Extractors</a>
<a class='left-prev' id="prev-link" href="../../guide/solvers/" title="previous page"><span class="section-number">8. </span>Solvers</a>
<a class='right-next' id="next-link" href="../collectors/" title="next page"><span class="section-number">10. </span>Collectors &amp; Extractors</a>
</div>
@ -549,7 +571,7 @@ commitment polytope. J Comb Optim 36, 1024-1058 (2018).
<div class="container">
<p>
&copy; Copyright 2020-2022, UChicago Argonne, LLC.<br/>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>

@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>9. Solvers &#8212; MIPLearn 0.3</title>
<title>12. Solvers &#8212; MIPLearn 0.3</title>
<link href="../../_static/css/theme.css" rel="stylesheet" />
<link href="../../_static/css/index.c5995385ac14fb8791e8eb36b4908be2.css" rel="stylesheet" />
@ -36,8 +36,8 @@
<script src="../../_static/sphinx-book-theme.12a9622fbb08dcb3a2a40b2c02b83a57.js"></script>
<link rel="index" title="Index" href="../../genindex/" />
<link rel="search" title="Search" href="../../search/" />
<link rel="next" title="10. Helpers" href="../helpers/" />
<link rel="prev" title="8. Components" href="../components/" />
<link rel="next" title="13. Helpers" href="../helpers/" />
<link rel="prev" title="11. Components" href="../components/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="docsearch:language" content="en" />
@ -66,6 +66,28 @@
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
@ -73,59 +95,59 @@
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../guide/problems/">
1. Benchmark Problems
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/collectors/">
2. Training Data Collectors
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/features/">
3. Feature Extractors
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/primal/">
4. Primal Components
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/solvers/">
5. Solvers
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
API Reference
Python API Reference
</span>
</p>
<ul class="current nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../problems/">
6. Benchmark Problems
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../collectors/">
7. Collectors &amp; Extractors
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../components/">
8. Components
11. Components
</a>
</li>
<li class="toctree-l1 current active">
<a class="current reference internal" href="#">
9. Solvers
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../helpers/">
10. Helpers
13. Helpers
</a>
</li>
</ul>
@ -197,17 +219,17 @@
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.solvers.abstract">
9.1. miplearn.solvers.abstract
12.1. miplearn.solvers.abstract
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.solvers.gurobi">
9.2. miplearn.solvers.gurobi
12.2. miplearn.solvers.gurobi
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#module-miplearn.solvers.learning">
9.3. miplearn.solvers.learning
12.3. miplearn.solvers.learning
</a>
</li>
</ul>
@ -222,9 +244,9 @@
<div>
<div class="section" id="solvers">
<h1><span class="section-number">9. </span>Solvers<a class="headerlink" href="#solvers" title="Permalink to this headline"></a></h1>
<h1><span class="section-number">12. </span>Solvers<a class="headerlink" href="#solvers" title="Permalink to this headline"></a></h1>
<div class="section" id="module-miplearn.solvers.abstract">
<span id="miplearn-solvers-abstract"></span><h2><span class="section-number">9.1. </span>miplearn.solvers.abstract<a class="headerlink" href="#module-miplearn.solvers.abstract" title="Permalink to this headline"></a></h2>
<span id="miplearn-solvers-abstract"></span><h2><span class="section-number">12.1. </span>miplearn.solvers.abstract<a class="headerlink" href="#module-miplearn.solvers.abstract" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.solvers.abstract.AbstractModel">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.solvers.abstract.</span></code><code class="sig-name descname"><span class="pre">AbstractModel</span></code><a class="headerlink" href="#miplearn.solvers.abstract.AbstractModel" title="Permalink to this definition"></a></dt>
@ -264,11 +286,6 @@
<em class="property"><span class="pre">abstract</span> </em><code class="sig-name descname"><span class="pre">relax</span></code><span class="sig-paren">(</span><span class="sig-paren">)</span> &#x2192; <a class="reference internal" href="#miplearn.solvers.abstract.AbstractModel" title="miplearn.solvers.abstract.AbstractModel"><span class="pre">miplearn.solvers.abstract.AbstractModel</span></a><a class="headerlink" href="#miplearn.solvers.abstract.AbstractModel.relax" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
<dt id="miplearn.solvers.abstract.AbstractModel.set_time_limit">
<em class="property"><span class="pre">abstract</span> </em><code class="sig-name descname"><span class="pre">set_time_limit</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">time_limit_sec</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">float</span></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">None</span><a class="headerlink" href="#miplearn.solvers.abstract.AbstractModel.set_time_limit" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
<dt id="miplearn.solvers.abstract.AbstractModel.set_warm_starts">
<em class="property"><span class="pre">abstract</span> </em><code class="sig-name descname"><span class="pre">set_warm_starts</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">var_names</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">var_values</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">numpy.ndarray</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">stats</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">Dict</span><span class="p"><span class="pre">]</span></span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span> &#x2192; <span class="pre">None</span><a class="headerlink" href="#miplearn.solvers.abstract.AbstractModel.set_warm_starts" title="Permalink to this definition"></a></dt>
@ -283,7 +300,7 @@
</div>
<div class="section" id="module-miplearn.solvers.gurobi">
<span id="miplearn-solvers-gurobi"></span><h2><span class="section-number">9.2. </span>miplearn.solvers.gurobi<a class="headerlink" href="#module-miplearn.solvers.gurobi" title="Permalink to this headline"></a></h2>
<span id="miplearn-solvers-gurobi"></span><h2><span class="section-number">12.2. </span>miplearn.solvers.gurobi<a class="headerlink" href="#module-miplearn.solvers.gurobi" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.solvers.gurobi.GurobiModel">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.solvers.gurobi.</span></code><code class="sig-name descname"><span class="pre">GurobiModel</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">inner</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">gurobipy.Model</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">find_violations</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">Callable</span><span class="p"><span class="pre">]</span></span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">fix_violations</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">Callable</span><span class="p"><span class="pre">]</span></span></span> <span class="o"><span class="pre">=</span></span> <span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.solvers.gurobi.GurobiModel" title="Permalink to this definition"></a></dt>
@ -349,19 +366,19 @@ solved, extracts dynamic problem features, such as optimal MIP solution.</p>
</div>
<div class="section" id="module-miplearn.solvers.learning">
<span id="miplearn-solvers-learning"></span><h2><span class="section-number">9.3. </span>miplearn.solvers.learning<a class="headerlink" href="#module-miplearn.solvers.learning" title="Permalink to this headline"></a></h2>
<span id="miplearn-solvers-learning"></span><h2><span class="section-number">12.3. </span>miplearn.solvers.learning<a class="headerlink" href="#module-miplearn.solvers.learning" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt id="miplearn.solvers.learning.LearningSolver">
<em class="property"><span class="pre">class</span> </em><code class="sig-prename descclassname"><span class="pre">miplearn.solvers.learning.</span></code><code class="sig-name descname"><span class="pre">LearningSolver</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">components</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">List</span><span class="p"><span class="pre">[</span></span><span class="pre">Any</span><span class="p"><span class="pre">]</span></span></span></em>, <em class="sig-param"><span class="n"><span class="pre">skip_lp</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.solvers.learning.LearningSolver" title="Permalink to this definition"></a></dt>
<dd><p>Bases: <code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></p>
<dl class="py method">
<dt id="miplearn.solvers.learning.LearningSolver.fit">
<code class="sig-name descname"><span class="pre">fit</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">train_filenames</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.solvers.learning.LearningSolver.fit" title="Permalink to this definition"></a></dt>
<code class="sig-name descname"><span class="pre">fit</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data_filenames</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.solvers.learning.LearningSolver.fit" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
<dt id="miplearn.solvers.learning.LearningSolver.optimize">
<code class="sig-name descname"><span class="pre">optimize</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data_filename</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">build_model</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.solvers.learning.LearningSolver.optimize" title="Permalink to this definition"></a></dt>
<code class="sig-name descname"><span class="pre">optimize</span></code><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">model</span></span><span class="p"><span class="pre">:</span></span> <span class="n"><span class="pre">Union</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">,</span> </span><a class="reference internal" href="#miplearn.solvers.abstract.AbstractModel" title="miplearn.solvers.abstract.AbstractModel"><span class="pre">miplearn.solvers.abstract.AbstractModel</span></a><span class="p"><span class="pre">]</span></span></span></em>, <em class="sig-param"><span class="n"><span class="pre">build_model</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#miplearn.solvers.learning.LearningSolver.optimize" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -375,8 +392,8 @@ solved, extracts dynamic problem features, such as optimal MIP solution.</p>
<div class='prev-next-bottom'>
<a class='left-prev' id="prev-link" href="../components/" title="previous page"><span class="section-number">8. </span>Components</a>
<a class='right-next' id="next-link" href="../helpers/" title="next page"><span class="section-number">10. </span>Helpers</a>
<a class='left-prev' id="prev-link" href="../components/" title="previous page"><span class="section-number">11. </span>Components</a>
<a class='right-next' id="next-link" href="../helpers/" title="next page"><span class="section-number">13. </span>Helpers</a>
</div>
@ -386,7 +403,7 @@ solved, extracts dynamic problem features, such as optimal MIP solution.</p>
<div class="container">
<p>
&copy; Copyright 2020-2022, UChicago Argonne, LLC.<br/>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>

@ -24,6 +24,14 @@
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../_static/sphinx-book-theme.acff12b8f9c144ce68a297486a2fa670.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/custom.css" />
<link rel="preload" as="script" href="../_static/js/index.1c5a1a01449ed65a7b51.js">
@ -64,6 +72,28 @@
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../tutorials/getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../tutorials/getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../tutorials/getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
@ -71,59 +101,59 @@
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../guide/problems/">
1. Benchmark Problems
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../guide/collectors/">
2. Training Data Collectors
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../guide/features/">
3. Feature Extractors
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../guide/primal/">
4. Primal Components
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../guide/solvers/">
5. Solvers
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
API Reference
Python API Reference
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../api/problems/">
6. Benchmark Problems
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../api/collectors/">
7. Collectors &amp; Extractors
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../api/components/">
8. Components
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../api/solvers/">
9. Solvers
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../api/helpers/">
10. Helpers
13. Helpers
</a>
</li>
</ul>
@ -208,8 +238,6 @@
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="../api/solvers/#miplearn.solvers.abstract.AbstractModel">AbstractModel (class in miplearn.solvers.abstract)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="../api/solvers/#miplearn.solvers.abstract.AbstractModel.add_constrs">add_constrs() (miplearn.solvers.abstract.AbstractModel method)</a>
<ul>
@ -217,6 +245,10 @@
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="../api/collectors/#miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor">AlvLouWeh2017Extractor (class in miplearn.extractors.AlvLouWeh2017)</a>
</li>
</ul></td>
</tr></table>
<h2 id="B">B</h2>
@ -254,8 +286,12 @@
<h2 id="C">C</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="../api/helpers/#miplearn.h5.H5File.close">close() (miplearn.h5.H5File method)</a>
</li>
<li><a href="../api/collectors/#miplearn.collectors.basic.BasicCollector.collect">collect() (miplearn.collectors.basic.BasicCollector method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="../api/components/#miplearn.components.primal.mem.MergeTopSolutions.construct">construct() (miplearn.components.primal.mem.MergeTopSolutions method)</a>
<ul>
@ -338,19 +374,43 @@
</li>
<li><a href="../api/helpers/#miplearn.h5.H5File.get_bytes">get_bytes() (miplearn.h5.H5File method)</a>
</li>
<li><a href="../api/collectors/#miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor.get_constr_features">get_constr_features() (miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor method)</a>
<ul>
<li><a href="../api/collectors/#miplearn.extractors.fields.H5FieldsExtractor.get_constr_features">(miplearn.extractors.fields.H5FieldsExtractor method)</a>
</li>
</ul></li>
<li><a href="../api/collectors/#miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor.get_instance_features">get_instance_features() (miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor method)</a>
<ul>
<li><a href="../api/collectors/#miplearn.extractors.fields.H5FieldsExtractor.get_instance_features">(miplearn.extractors.fields.H5FieldsExtractor method)</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="../api/helpers/#miplearn.h5.H5File.get_scalar">get_scalar() (miplearn.h5.H5File method)</a>
</li>
<li><a href="../api/helpers/#miplearn.h5.H5File.get_sparse">get_sparse() (miplearn.h5.H5File method)</a>
</li>
<li><a href="../api/collectors/#miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor.get_var_features">get_var_features() (miplearn.extractors.AlvLouWeh2017.AlvLouWeh2017Extractor method)</a>
<ul>
<li><a href="../api/collectors/#miplearn.extractors.fields.H5FieldsExtractor.get_var_features">(miplearn.extractors.fields.H5FieldsExtractor method)</a>
</li>
</ul></li>
<li><a href="../api/solvers/#miplearn.solvers.gurobi.GurobiModel">GurobiModel (class in miplearn.solvers.gurobi)</a>
</li>
<li><a href="../api/helpers/#miplearn.io.gzip">gzip() (in module miplearn.io)</a>
</li>
</ul></td>
</tr></table>
<h2 id="H">H</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="../api/collectors/#miplearn.extractors.fields.H5FieldsExtractor">H5FieldsExtractor (class in miplearn.extractors.fields)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="../api/helpers/#miplearn.h5.H5File">H5File (class in miplearn.h5)</a>
</li>
@ -377,10 +437,6 @@
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="../api/solvers/#miplearn.solvers.learning.LearningSolver">LearningSolver (class in miplearn.solvers.learning)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="../api/helpers/#miplearn.io.load">load() (in module miplearn.io)</a>
</li>
</ul></td>
</tr></table>
@ -454,6 +510,20 @@
<ul>
<li><a href="../api/components/#module-miplearn.components.primal.mem">module</a>
</li>
</ul></li>
<li>
miplearn.extractors.AlvLouWeh2017
<ul>
<li><a href="../api/collectors/#module-miplearn.extractors.AlvLouWeh2017">module</a>
</li>
</ul></li>
<li>
miplearn.extractors.fields
<ul>
<li><a href="../api/collectors/#module-miplearn.extractors.fields">module</a>
</li>
</ul></li>
<li>
@ -505,6 +575,8 @@
<li><a href="../api/problems/#module-miplearn.problems.setpack">module</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li>
miplearn.problems.stab
@ -512,8 +584,6 @@
<li><a href="../api/problems/#module-miplearn.problems.stab">module</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li>
miplearn.problems.tsp
@ -575,6 +645,10 @@
<li><a href="../api/components/#module-miplearn.components.primal.joint">miplearn.components.primal.joint</a>
</li>
<li><a href="../api/components/#module-miplearn.components.primal.mem">miplearn.components.primal.mem</a>
</li>
<li><a href="../api/collectors/#module-miplearn.extractors.AlvLouWeh2017">miplearn.extractors.AlvLouWeh2017</a>
</li>
<li><a href="../api/collectors/#module-miplearn.extractors.fields">miplearn.extractors.fields</a>
</li>
<li><a href="../api/helpers/#module-miplearn.h5">miplearn.h5</a>
</li>
@ -666,6 +740,10 @@
<h2 id="R">R</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="../api/helpers/#miplearn.io.read_pkl_gz">read_pkl_gz() (in module miplearn.io)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="../api/solvers/#miplearn.solvers.abstract.AbstractModel.relax">relax() (miplearn.solvers.abstract.AbstractModel method)</a>
@ -679,16 +757,10 @@
<h2 id="S">S</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="../api/helpers/#miplearn.io.save">save() (in module miplearn.io)</a>
</li>
<li><a href="../api/components/#miplearn.components.primal.mem.SelectTopSolutions">SelectTopSolutions (class in miplearn.components.primal.mem)</a>
</li>
<li><a href="../api/solvers/#miplearn.solvers.abstract.AbstractModel.set_time_limit">set_time_limit() (miplearn.solvers.abstract.AbstractModel method)</a>
<ul>
<li><a href="../api/solvers/#miplearn.solvers.gurobi.GurobiModel.set_time_limit">(miplearn.solvers.gurobi.GurobiModel method)</a>
<li><a href="../api/solvers/#miplearn.solvers.gurobi.GurobiModel.set_time_limit">set_time_limit() (miplearn.solvers.gurobi.GurobiModel method)</a>
</li>
</ul></li>
<li><a href="../api/solvers/#miplearn.solvers.abstract.AbstractModel.set_warm_starts">set_warm_starts() (miplearn.solvers.abstract.AbstractModel method)</a>
<ul>
@ -740,6 +812,10 @@
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="../api/helpers/#miplearn.io.write_pkl_gz">write_pkl_gz() (in module miplearn.io)</a>
</li>
</ul></td>
</tr></table>
@ -758,7 +834,7 @@
<div class="container">
<p>
&copy; Copyright 2020-2022, UChicago Argonne, LLC.<br/>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>

@ -38,8 +38,8 @@
},
{
"cell_type": "code",
"execution_count": 1,
"id": "3d9cc182",
"execution_count": 3,
"id": "6d342a4e",
"metadata": {
"collapsed": false
},
@ -103,7 +103,7 @@
},
{
"cell_type": "markdown",
"id": "e7175752",
"id": "8a46bb8a",
"metadata": {
"collapsed": false
},
@ -111,7 +111,7 @@
},
{
"cell_type": "markdown",
"id": "e993aa6f",
"id": "d8699092",
"metadata": {
"collapsed": false
},
@ -131,7 +131,7 @@
},
{
"cell_type": "markdown",
"id": "711639bd",
"id": "99a122dc",
"metadata": {
"collapsed": false
},
@ -172,7 +172,7 @@
},
{
"cell_type": "markdown",
"id": "9b35d7f7",
"id": "7fe76973",
"metadata": {
"collapsed": false
},
@ -184,25 +184,16 @@
},
{
"cell_type": "code",
"execution_count": 2,
"id": "7ea6b715",
"execution_count": 4,
"id": "425717fe",
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/axavier/Software/anaconda3/envs/miplearn/lib/python3.8/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Removing empty/corrupted h5 file: data/tsp/00000.h5\n",
"lp_obj_value = 2909.0\n",
"mip_obj_value = 2921.0\n"
]
@ -218,7 +209,7 @@
" TravelingSalesmanGenerator,\n",
" build_tsp_model,\n",
")\n",
"from miplearn.io import save\n",
"from miplearn.io import write_pkl_gz\n",
"from miplearn.h5 import H5File\n",
"from miplearn.collectors.basic import BasicCollector\n",
"\n",
@ -237,11 +228,11 @@
").generate(10)\n",
"\n",
"# Save instance data to data/tsp/00000.pkl.gz, data/tsp/00001.pkl.gz, ...\n",
"save(data, \"data/tsp\")\n",
"write_pkl_gz(data, \"data/tsp\")\n",
"\n",
"# Solve all instances and collect basic solution information. Process at most four\n",
"# instances in parallel, with a per-instance time limit of one hour.\n",
"bc = BasicCollector(time_limit_sec=3600)\n",
"# Solve all instances and collect basic solution information.\n",
"# Process at most four instances in parallel.\n",
"bc = BasicCollector()\n",
"bc.collect(glob(\"data/tsp/*.pkl.gz\"), build_tsp_model, n_jobs=4)\n",
"\n",
"# Read and print some training data for the first instance.\n",
@ -252,8 +243,8 @@
},
{
"cell_type": "code",
"execution_count": 2,
"id": "97ac9136",
"execution_count": null,
"id": "30023d2b",
"metadata": {
"collapsed": false
},
@ -277,7 +268,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.13"
"version": "3.9.12"
}
},
"nbformat": 4,

@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>2. Training Data Collectors &#8212; MIPLearn 0.3</title>
<title>5. Training Data Collectors &#8212; MIPLearn 0.3</title>
<link href="../../_static/css/theme.css" rel="stylesheet" />
<link href="../../_static/css/index.c5995385ac14fb8791e8eb36b4908be2.css" rel="stylesheet" />
@ -24,6 +24,7 @@
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../_static/sphinx-book-theme.acff12b8f9c144ce68a297486a2fa670.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/custom.css" />
<link rel="preload" as="script" href="../../_static/js/index.1c5a1a01449ed65a7b51.js">
@ -38,8 +39,8 @@
<script type="text/x-mathjax-config">MathJax.Hub.Config({"tex2jax": {"inlineMath": [["\\(", "\\)"]], "displayMath": [["\\[", "\\]"]], "processRefs": false, "processEnvironments": false}})</script>
<link rel="index" title="Index" href="../../genindex/" />
<link rel="search" title="Search" href="../../search/" />
<link rel="next" title="3. Feature Extractors" href="../features/" />
<link rel="prev" title="1. Benchmark Problems" href="../problems/" />
<link rel="next" title="6. Feature Extractors" href="../features/" />
<link rel="prev" title="4. Benchmark Problems" href="../problems/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="docsearch:language" content="en" />
@ -68,6 +69,28 @@
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
@ -75,59 +98,59 @@
<ul class="current nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../problems/">
1. Benchmark Problems
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1 current active">
<a class="current reference internal" href="#">
2. Training Data Collectors
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../features/">
3. Feature Extractors
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../primal/">
4. Primal Components
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../solvers/">
5. Solvers
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
API Reference
Python API Reference
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../api/problems/">
6. Benchmark Problems
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/collectors/">
7. Collectors &amp; Extractors
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/components/">
8. Components
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/solvers/">
9. Solvers
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/helpers/">
10. Helpers
13. Helpers
</a>
</li>
</ul>
@ -199,12 +222,12 @@
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Overview">
2.1. Overview
5.1. Overview
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#HDF5-Format">
2.2. HDF5 Format
5.2. HDF5 Format
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -216,7 +239,7 @@
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Basic-collector">
2.3. Basic collector
5.3. Basic collector
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -242,279 +265,22 @@
<div>
<style>
/* CSS for nbsphinx extension */
/* remove conflicting styling from Sphinx themes */
div.nbinput.container div.prompt *,
div.nboutput.container div.prompt *,
div.nbinput.container div.input_area pre,
div.nboutput.container div.output_area pre,
div.nbinput.container div.input_area .highlight,
div.nboutput.container div.output_area .highlight {
border: none;
padding: 0;
margin: 0;
box-shadow: none;
}
div.nbinput.container > div[class*=highlight],
div.nboutput.container > div[class*=highlight] {
margin: 0;
}
div.nbinput.container div.prompt *,
div.nboutput.container div.prompt * {
background: none;
}
div.nboutput.container div.output_area .highlight,
div.nboutput.container div.output_area pre {
background: unset;
}
div.nboutput.container div.output_area div.highlight {
color: unset; /* override Pygments text color */
}
/* avoid gaps between output lines */
div.nboutput.container div[class*=highlight] pre {
line-height: normal;
}
/* input/output containers */
div.nbinput.container,
div.nboutput.container {
display: -webkit-flex;
display: flex;
align-items: flex-start;
margin: 0;
width: 100%;
}
@media (max-width: 540px) {
div.nbinput.container,
div.nboutput.container {
flex-direction: column;
}
}
/* input container */
div.nbinput.container {
padding-top: 5px;
}
/* last container */
div.nblast.container {
padding-bottom: 5px;
}
/* input prompt */
div.nbinput.container div.prompt pre {
color: #307FC1;
}
/* output prompt */
div.nboutput.container div.prompt pre {
color: #BF5B3D;
}
/* all prompts */
div.nbinput.container div.prompt,
div.nboutput.container div.prompt {
width: 4.5ex;
padding-top: 5px;
position: relative;
user-select: none;
}
div.nbinput.container div.prompt > div,
div.nboutput.container div.prompt > div {
position: absolute;
right: 0;
margin-right: 0.3ex;
}
@media (max-width: 540px) {
div.nbinput.container div.prompt,
div.nboutput.container div.prompt {
width: unset;
text-align: left;
padding: 0.4em;
}
div.nboutput.container div.prompt.empty {
padding: 0;
}
div.nbinput.container div.prompt > div,
div.nboutput.container div.prompt > div {
position: unset;
}
}
/* disable scrollbars and line breaks on prompts */
div.nbinput.container div.prompt pre,
div.nboutput.container div.prompt pre {
overflow: hidden;
white-space: pre;
}
/* input/output area */
div.nbinput.container div.input_area,
div.nboutput.container div.output_area {
-webkit-flex: 1;
flex: 1;
overflow: auto;
}
@media (max-width: 540px) {
div.nbinput.container div.input_area,
div.nboutput.container div.output_area {
width: 100%;
}
}
/* input area */
div.nbinput.container div.input_area {
border: 1px solid #e0e0e0;
border-radius: 2px;
/*background: #f5f5f5;*/
}
/* override MathJax center alignment in output cells */
div.nboutput.container div[class*=MathJax] {
text-align: left !important;
}
/* override sphinx.ext.imgmath center alignment in output cells */
div.nboutput.container div.math p {
text-align: left;
}
/* standard error */
div.nboutput.container div.output_area.stderr {
background: #fdd;
}
/* ANSI colors */
.ansi-black-fg { color: #3E424D; }
.ansi-black-bg { background-color: #3E424D; }
.ansi-black-intense-fg { color: #282C36; }
.ansi-black-intense-bg { background-color: #282C36; }
.ansi-red-fg { color: #E75C58; }
.ansi-red-bg { background-color: #E75C58; }
.ansi-red-intense-fg { color: #B22B31; }
.ansi-red-intense-bg { background-color: #B22B31; }
.ansi-green-fg { color: #00A250; }
.ansi-green-bg { background-color: #00A250; }
.ansi-green-intense-fg { color: #007427; }
.ansi-green-intense-bg { background-color: #007427; }
.ansi-yellow-fg { color: #DDB62B; }
.ansi-yellow-bg { background-color: #DDB62B; }
.ansi-yellow-intense-fg { color: #B27D12; }
.ansi-yellow-intense-bg { background-color: #B27D12; }
.ansi-blue-fg { color: #208FFB; }
.ansi-blue-bg { background-color: #208FFB; }
.ansi-blue-intense-fg { color: #0065CA; }
.ansi-blue-intense-bg { background-color: #0065CA; }
.ansi-magenta-fg { color: #D160C4; }
.ansi-magenta-bg { background-color: #D160C4; }
.ansi-magenta-intense-fg { color: #A03196; }
.ansi-magenta-intense-bg { background-color: #A03196; }
.ansi-cyan-fg { color: #60C6C8; }
.ansi-cyan-bg { background-color: #60C6C8; }
.ansi-cyan-intense-fg { color: #258F8F; }
.ansi-cyan-intense-bg { background-color: #258F8F; }
.ansi-white-fg { color: #C5C1B4; }
.ansi-white-bg { background-color: #C5C1B4; }
.ansi-white-intense-fg { color: #A1A6B2; }
.ansi-white-intense-bg { background-color: #A1A6B2; }
.ansi-default-inverse-fg { color: #FFFFFF; }
.ansi-default-inverse-bg { background-color: #000000; }
.ansi-bold { font-weight: bold; }
.ansi-underline { text-decoration: underline; }
div.nbinput.container div.input_area div[class*=highlight] > pre,
div.nboutput.container div.output_area div[class*=highlight] > pre,
div.nboutput.container div.output_area div[class*=highlight].math,
div.nboutput.container div.output_area.rendered_html,
div.nboutput.container div.output_area > div.output_javascript,
div.nboutput.container div.output_area:not(.rendered_html) > img{
padding: 5px;
margin: 0;
}
/* fix copybtn overflow problem in chromium (needed for 'sphinx_copybutton') */
div.nbinput.container div.input_area > div[class^='highlight'],
div.nboutput.container div.output_area > div[class^='highlight']{
overflow-y: hidden;
}
/* hide copybtn icon on prompts (needed for 'sphinx_copybutton') */
.prompt .copybtn {
display: none;
}
/* Some additional styling taken form the Jupyter notebook CSS */
.jp-RenderedHTMLCommon table,
div.rendered_html table {
border: none;
border-collapse: collapse;
border-spacing: 0;
color: black;
font-size: 12px;
table-layout: fixed;
}
.jp-RenderedHTMLCommon thead,
div.rendered_html thead {
border-bottom: 1px solid black;
vertical-align: bottom;
}
.jp-RenderedHTMLCommon tr,
.jp-RenderedHTMLCommon th,
.jp-RenderedHTMLCommon td,
div.rendered_html tr,
div.rendered_html th,
div.rendered_html td {
text-align: right;
vertical-align: middle;
padding: 0.5em 0.5em;
line-height: normal;
white-space: normal;
max-width: none;
border: none;
}
.jp-RenderedHTMLCommon th,
div.rendered_html th {
font-weight: bold;
}
.jp-RenderedHTMLCommon tbody tr:nth-child(odd),
div.rendered_html tbody tr:nth-child(odd) {
background: #f5f5f5;
}
.jp-RenderedHTMLCommon tbody tr:hover,
div.rendered_html tbody tr:hover {
background: rgba(66, 165, 245, 0.2);
}
</style>
<div class="section" id="Training-Data-Collectors">
<h1><span class="section-number">2. </span>Training Data Collectors<a class="headerlink" href="#Training-Data-Collectors" title="Permalink to this headline"></a></h1>
<div class="section" id="Training-Data-Collectors">
<h1><span class="section-number">5. </span>Training Data Collectors<a class="headerlink" href="#Training-Data-Collectors" title="Permalink to this headline"></a></h1>
<p>The first step in solving mixed-integer optimization problems with the assistance of supervised machine learning methods is solving a large set of training instances and collecting the raw training data. In this section, we describe the various training data collectors included in MIPLearn. Additionally, the framework follows the convention of storing all training data in files with a specific data format (namely, HDF5). In this section, we briefly describe this format and the rationale for
choosing it.</p>
<div class="section" id="Overview">
<h2><span class="section-number">2.1. </span>Overview<a class="headerlink" href="#Overview" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">5.1. </span>Overview<a class="headerlink" href="#Overview" title="Permalink to this headline"></a></h2>
<p>In MIPLearn, a <strong>collector</strong> is a class that solves or analyzes the problem and collects raw data which may be later useful for machine learning methods. Collectors, by convention, take as input: (i) a list of problem data filenames, in gzipped pickle format, ending with <code class="docutils literal notranslate"><span class="pre">.pkl.gz</span></code>; (ii) a function that builds the optimization model, such as <code class="docutils literal notranslate"><span class="pre">build_tsp_model</span></code>. After processing is done, collectors store the training data in a HDF5 file located alongside with the problem data. For example, if
the problem data is stored in file <code class="docutils literal notranslate"><span class="pre">problem.pkl.gz</span></code>, then the collector writes to <code class="docutils literal notranslate"><span class="pre">problem.h5</span></code>. Collectors are, in general, very time consuming, as they may need to solve the problem to optimality, potentially multiple times.</p>
</div>
<div class="section" id="HDF5-Format">
<h2><span class="section-number">2.2. </span>HDF5 Format<a class="headerlink" href="#HDF5-Format" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">5.2. </span>HDF5 Format<a class="headerlink" href="#HDF5-Format" title="Permalink to this headline"></a></h2>
<p>MIPLearn stores all training data in <a class="reference external" href="HDF5">HDF5</a> (Hierarchical Data Format, Version 5) files. The HDF format was originally developed by the <a class="reference external" href="https://en.wikipedia.org/wiki/National_Center_for_Supercomputing_Applications">National Center for Supercomputing Applications</a> (NCSA) for storing and organizing large amounts of data, and supports a variety of data types, including integers, floating-point numbers, strings, and arrays. Compared to other formats, such as CSV, JSON or SQLite, the
HDF5 format provides several advantages for MIPLearn, including:</p>
<ul class="simple">
<li><p><em>Storage of multiple scalars, vectors and matrices in a single file</em> — This allows MIPLearn to store all training data related to a given problem instance in a single file, which makes training data easier to store, organize and transfer.</p></li>
<li><p><em>High-performance partial I/O</em> — Partial I/O allows MIPLearn to read a single element from the training data (e.g. value of the optimal solution) without loading the entire file to memory or reading it from beginning to end, which dramatically improves performance and reduces memory requirements. This is especially important when processing a large number of training data files.</p></li>
<li><p><em>High-performance partial I/O</em> — Partial I/O allows MIPLearn to read a single element from the training data (e.g. value of the optimal solution) without loading the entire file to memory or reading it from beginning to end, which dramatically improves performance and reduces memory requirements. This is especially important when processing a large number of training data files.</p></li>
<li><p><em>On-the-fly compression</em> — HDF5 files can be transparently compressed, using the gzip method, which reduces storage requirements and accelerates network transfers.</p></li>
<li><p><em>Stable, portable and well-supported data format</em> — Training data files are typically expensive to generate. Having a stable and well supported data format ensures that these files remain usable in the future, potentially even by other non-Python MIP/ML frameworks.</p></li>
</ul>
@ -524,7 +290,7 @@ automatically perform type-checking and gzip compression. The example below show
<div class="section" id="Example">
<h3>Example<a class="headerlink" href="#Example" title="Permalink to this headline"></a></h3>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[1]:
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[3]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
@ -587,7 +353,7 @@ x5 = (2, 3) 0.68030757
</div>
</div>
<div class="section" id="Basic-collector">
<h2><span class="section-number">2.3. </span>Basic collector<a class="headerlink" href="#Basic-collector" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">5.3. </span>Basic collector<a class="headerlink" href="#Basic-collector" title="Permalink to this headline"></a></h2>
<p><a class="reference external" href="../../api/collectors/#miplearn.collectors.basic.BasicCollector">BasicCollector</a> is the most fundamental collector, and performs the following steps:</p>
<ol class="arabic simple">
<li><p>Extracts all model data, such as objective function and constraint right-hand sides into numpy arrays, which can later be easily and efficiently accessed without rebuilding the model or invoking the solver;</p></li>
@ -729,7 +495,7 @@ x5 = (2, 3) 0.68030757
<h3>Example<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3>
<p>The example below shows how to generate a few random instances of the traveling salesman problem, store its problem data, run the collector and print some of the training data to screen.</p>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[2]:
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[4]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">random</span>
@ -741,7 +507,7 @@ x5 = (2, 3) 0.68030757
<span class="n">TravelingSalesmanGenerator</span><span class="p">,</span>
<span class="n">build_tsp_model</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">miplearn.io</span> <span class="kn">import</span> <span class="n">save</span>
<span class="kn">from</span> <span class="nn">miplearn.io</span> <span class="kn">import</span> <span class="n">write_pkl_gz</span>
<span class="kn">from</span> <span class="nn">miplearn.h5</span> <span class="kn">import</span> <span class="n">H5File</span>
<span class="kn">from</span> <span class="nn">miplearn.collectors.basic</span> <span class="kn">import</span> <span class="n">BasicCollector</span>
@ -760,11 +526,11 @@ x5 = (2, 3) 0.68030757
<span class="p">)</span><span class="o">.</span><span class="n">generate</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
<span class="c1"># Save instance data to data/tsp/00000.pkl.gz, data/tsp/00001.pkl.gz, ...</span>
<span class="n">save</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="s2">&quot;data/tsp&quot;</span><span class="p">)</span>
<span class="n">write_pkl_gz</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="s2">&quot;data/tsp&quot;</span><span class="p">)</span>
<span class="c1"># Solve all instances and collect basic solution information. Process at most four</span>
<span class="c1"># instances in parallel, with a per-instance time limit of one hour.</span>
<span class="n">bc</span> <span class="o">=</span> <span class="n">BasicCollector</span><span class="p">(</span><span class="n">time_limit_sec</span><span class="o">=</span><span class="mi">3600</span><span class="p">)</span>
<span class="c1"># Solve all instances and collect basic solution information.</span>
<span class="c1"># Process at most four instances in parallel.</span>
<span class="n">bc</span> <span class="o">=</span> <span class="n">BasicCollector</span><span class="p">()</span>
<span class="n">bc</span><span class="o">.</span><span class="n">collect</span><span class="p">(</span><span class="n">glob</span><span class="p">(</span><span class="s2">&quot;data/tsp/*.pkl.gz&quot;</span><span class="p">),</span> <span class="n">build_tsp_model</span><span class="p">,</span> <span class="n">n_jobs</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
<span class="c1"># Read and print some training data for the first instance.</span>
@ -774,27 +540,17 @@ x5 = (2, 3) 0.68030757
</pre></div>
</div>
</div>
<div class="nboutput docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area stderr docutils container">
<div class="highlight"><pre>
/home/axavier/Software/anaconda3/envs/miplearn/lib/python3.8/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
</pre></div></div>
</div>
<div class="nboutput nblast docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area docutils container">
<div class="highlight"><pre>
Removing empty/corrupted h5 file: data/tsp/00000.h5
lp_obj_value = 2909.0
mip_obj_value = 2921.0
</pre></div></div>
</div>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[2]:
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[ ]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span>
@ -811,8 +567,8 @@ mip_obj_value = 2921.0
<div class='prev-next-bottom'>
<a class='left-prev' id="prev-link" href="../problems/" title="previous page"><span class="section-number">1. </span>Benchmark Problems</a>
<a class='right-next' id="next-link" href="../features/" title="next page"><span class="section-number">3. </span>Feature Extractors</a>
<a class='left-prev' id="prev-link" href="../problems/" title="previous page"><span class="section-number">4. </span>Benchmark Problems</a>
<a class='right-next' id="next-link" href="../features/" title="next page"><span class="section-number">6. </span>Feature Extractors</a>
</div>
@ -822,7 +578,7 @@ mip_obj_value = 2921.0
<div class="container">
<p>
&copy; Copyright 2020-2022, UChicago Argonne, LLC.<br/>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>

@ -12,7 +12,7 @@
},
{
"cell_type": "markdown",
"id": "599ac2f7",
"id": "94df359d",
"metadata": {
"collapsed": false
},
@ -32,7 +32,7 @@
},
{
"cell_type": "markdown",
"id": "60efe8f5",
"id": "d450370d",
"metadata": {
"collapsed": false
},
@ -45,7 +45,7 @@
},
{
"cell_type": "markdown",
"id": "dfc32e59",
"id": "b0e96d25",
"metadata": {
"collapsed": false
},
@ -57,8 +57,8 @@
},
{
"cell_type": "code",
"execution_count": 1,
"id": "ed2f5006",
"execution_count": 5,
"id": "82609250",
"metadata": {
"collapsed": false
},
@ -99,12 +99,12 @@
"from scipy.stats import uniform, randint\n",
"\n",
"from miplearn.collectors.basic import BasicCollector\n",
"from miplearn.features.fields import H5FieldsExtractor\n",
"from miplearn.extractors.fields import H5FieldsExtractor\n",
"from miplearn.h5 import H5File\n",
"from miplearn.io import save\n",
"from miplearn.io import write_pkl_gz\n",
"from miplearn.problems.multiknapsack import (\n",
" MultiKnapsackGenerator,\n",
" build_multiknapsack_model\n",
" build_multiknapsack_model,\n",
")\n",
"\n",
"# Set random seed to make example reproducible\n",
@ -112,7 +112,7 @@
"\n",
"# Generate some random multiknapsack instances\n",
"rmtree(\"data/multiknapsack/\", ignore_errors=True)\n",
"save(\n",
"write_pkl_gz(\n",
" MultiKnapsackGenerator(\n",
" n=randint(low=10, high=11),\n",
" m=randint(low=5, high=6),\n",
@ -124,7 +124,7 @@
" p_jitter=uniform(loc=0.75, scale=0.5),\n",
" fix_w=True,\n",
" ).generate(10),\n",
" \"data/multiknapsack\"\n",
" \"data/multiknapsack\",\n",
")\n",
"\n",
"# Run the basic collector\n",
@ -155,7 +155,7 @@
" \"static_constr_rhs\",\n",
" \"lp_constr_dual_values\",\n",
" \"lp_constr_slacks\",\n",
" ]\n",
" ],\n",
")\n",
"\n",
"with H5File(\"data/multiknapsack/00000.h5\") as h5:\n",
@ -174,7 +174,7 @@
},
{
"cell_type": "markdown",
"id": "35dc7ce3",
"id": "b6912b56",
"metadata": {
"collapsed": false
},
@ -185,7 +185,7 @@
},
{
"cell_type": "markdown",
"id": "cc32efd6",
"id": "81fd1d27",
"metadata": {
"collapsed": false
},
@ -199,7 +199,7 @@
},
{
"cell_type": "markdown",
"id": "2e3ba4fe",
"id": "fdbf5674",
"metadata": {
"collapsed": false
},
@ -213,8 +213,8 @@
},
{
"cell_type": "code",
"execution_count": 5,
"id": "4944a4a4",
"execution_count": 6,
"id": "85ef526d",
"metadata": {
"collapsed": false
},
@ -288,7 +288,7 @@
}
],
"source": [
"from miplearn.features.AlvLouWeh2017 import AlvLouWeh2017Extractor\n",
"from miplearn.extractors.AlvLouWeh2017 import AlvLouWeh2017Extractor\n",
"from miplearn.h5 import H5File\n",
"\n",
"# Build the extractor\n",
@ -296,7 +296,6 @@
"\n",
"# Open previously-created multiknapsack training data\n",
"with H5File(\"data/multiknapsack/00000.h5\") as h5:\n",
"\n",
" # Extract and print variable features\n",
" x1 = ext.get_var_features(h5)\n",
" print(\"x1\", x1.shape, \"\\n\", x1.round(1))"
@ -304,7 +303,7 @@
},
{
"cell_type": "markdown",
"id": "04eab813",
"id": "3e17c5f8",
"metadata": {
"collapsed": false
},
@ -335,7 +334,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.13"
"version": "3.9.12"
}
},
"nbformat": 4,

@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>3. Feature Extractors &#8212; MIPLearn 0.3</title>
<title>6. Feature Extractors &#8212; MIPLearn 0.3</title>
<link href="../../_static/css/theme.css" rel="stylesheet" />
<link href="../../_static/css/index.c5995385ac14fb8791e8eb36b4908be2.css" rel="stylesheet" />
@ -24,6 +24,8 @@
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../_static/sphinx-book-theme.acff12b8f9c144ce68a297486a2fa670.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/custom.css" />
<link rel="preload" as="script" href="../../_static/js/index.1c5a1a01449ed65a7b51.js">
@ -38,8 +40,8 @@
<script type="text/x-mathjax-config">MathJax.Hub.Config({"tex2jax": {"inlineMath": [["\\(", "\\)"]], "displayMath": [["\\[", "\\]"]], "processRefs": false, "processEnvironments": false}})</script>
<link rel="index" title="Index" href="../../genindex/" />
<link rel="search" title="Search" href="../../search/" />
<link rel="next" title="4. Primal Components" href="../primal/" />
<link rel="prev" title="2. Training Data Collectors" href="../collectors/" />
<link rel="next" title="7. Primal Components" href="../primal/" />
<link rel="prev" title="5. Training Data Collectors" href="../collectors/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="docsearch:language" content="en" />
@ -68,6 +70,28 @@
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
@ -75,59 +99,59 @@
<ul class="current nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../problems/">
1. Benchmark Problems
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../collectors/">
2. Training Data Collectors
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1 current active">
<a class="current reference internal" href="#">
3. Feature Extractors
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../primal/">
4. Primal Components
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../solvers/">
5. Solvers
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
API Reference
Python API Reference
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../api/problems/">
6. Benchmark Problems
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/collectors/">
7. Collectors &amp; Extractors
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/components/">
8. Components
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/solvers/">
9. Solvers
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/helpers/">
10. Helpers
13. Helpers
</a>
</li>
</ul>
@ -199,12 +223,12 @@
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Overview">
3.1. Overview
6.1. Overview
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#H5FieldsExtractor">
3.2. H5FieldsExtractor
6.2. H5FieldsExtractor
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -216,7 +240,7 @@
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#AlvLouWeh2017Extractor">
3.3. AlvLouWeh2017Extractor
6.3. AlvLouWeh2017Extractor
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -237,268 +261,11 @@
<div>
<style>
/* CSS for nbsphinx extension */
/* remove conflicting styling from Sphinx themes */
div.nbinput.container div.prompt *,
div.nboutput.container div.prompt *,
div.nbinput.container div.input_area pre,
div.nboutput.container div.output_area pre,
div.nbinput.container div.input_area .highlight,
div.nboutput.container div.output_area .highlight {
border: none;
padding: 0;
margin: 0;
box-shadow: none;
}
div.nbinput.container > div[class*=highlight],
div.nboutput.container > div[class*=highlight] {
margin: 0;
}
div.nbinput.container div.prompt *,
div.nboutput.container div.prompt * {
background: none;
}
div.nboutput.container div.output_area .highlight,
div.nboutput.container div.output_area pre {
background: unset;
}
div.nboutput.container div.output_area div.highlight {
color: unset; /* override Pygments text color */
}
/* avoid gaps between output lines */
div.nboutput.container div[class*=highlight] pre {
line-height: normal;
}
/* input/output containers */
div.nbinput.container,
div.nboutput.container {
display: -webkit-flex;
display: flex;
align-items: flex-start;
margin: 0;
width: 100%;
}
@media (max-width: 540px) {
div.nbinput.container,
div.nboutput.container {
flex-direction: column;
}
}
/* input container */
div.nbinput.container {
padding-top: 5px;
}
/* last container */
div.nblast.container {
padding-bottom: 5px;
}
/* input prompt */
div.nbinput.container div.prompt pre {
color: #307FC1;
}
/* output prompt */
div.nboutput.container div.prompt pre {
color: #BF5B3D;
}
/* all prompts */
div.nbinput.container div.prompt,
div.nboutput.container div.prompt {
width: 4.5ex;
padding-top: 5px;
position: relative;
user-select: none;
}
div.nbinput.container div.prompt > div,
div.nboutput.container div.prompt > div {
position: absolute;
right: 0;
margin-right: 0.3ex;
}
@media (max-width: 540px) {
div.nbinput.container div.prompt,
div.nboutput.container div.prompt {
width: unset;
text-align: left;
padding: 0.4em;
}
div.nboutput.container div.prompt.empty {
padding: 0;
}
div.nbinput.container div.prompt > div,
div.nboutput.container div.prompt > div {
position: unset;
}
}
/* disable scrollbars and line breaks on prompts */
div.nbinput.container div.prompt pre,
div.nboutput.container div.prompt pre {
overflow: hidden;
white-space: pre;
}
/* input/output area */
div.nbinput.container div.input_area,
div.nboutput.container div.output_area {
-webkit-flex: 1;
flex: 1;
overflow: auto;
}
@media (max-width: 540px) {
div.nbinput.container div.input_area,
div.nboutput.container div.output_area {
width: 100%;
}
}
/* input area */
div.nbinput.container div.input_area {
border: 1px solid #e0e0e0;
border-radius: 2px;
/*background: #f5f5f5;*/
}
/* override MathJax center alignment in output cells */
div.nboutput.container div[class*=MathJax] {
text-align: left !important;
}
/* override sphinx.ext.imgmath center alignment in output cells */
div.nboutput.container div.math p {
text-align: left;
}
/* standard error */
div.nboutput.container div.output_area.stderr {
background: #fdd;
}
/* ANSI colors */
.ansi-black-fg { color: #3E424D; }
.ansi-black-bg { background-color: #3E424D; }
.ansi-black-intense-fg { color: #282C36; }
.ansi-black-intense-bg { background-color: #282C36; }
.ansi-red-fg { color: #E75C58; }
.ansi-red-bg { background-color: #E75C58; }
.ansi-red-intense-fg { color: #B22B31; }
.ansi-red-intense-bg { background-color: #B22B31; }
.ansi-green-fg { color: #00A250; }
.ansi-green-bg { background-color: #00A250; }
.ansi-green-intense-fg { color: #007427; }
.ansi-green-intense-bg { background-color: #007427; }
.ansi-yellow-fg { color: #DDB62B; }
.ansi-yellow-bg { background-color: #DDB62B; }
.ansi-yellow-intense-fg { color: #B27D12; }
.ansi-yellow-intense-bg { background-color: #B27D12; }
.ansi-blue-fg { color: #208FFB; }
.ansi-blue-bg { background-color: #208FFB; }
.ansi-blue-intense-fg { color: #0065CA; }
.ansi-blue-intense-bg { background-color: #0065CA; }
.ansi-magenta-fg { color: #D160C4; }
.ansi-magenta-bg { background-color: #D160C4; }
.ansi-magenta-intense-fg { color: #A03196; }
.ansi-magenta-intense-bg { background-color: #A03196; }
.ansi-cyan-fg { color: #60C6C8; }
.ansi-cyan-bg { background-color: #60C6C8; }
.ansi-cyan-intense-fg { color: #258F8F; }
.ansi-cyan-intense-bg { background-color: #258F8F; }
.ansi-white-fg { color: #C5C1B4; }
.ansi-white-bg { background-color: #C5C1B4; }
.ansi-white-intense-fg { color: #A1A6B2; }
.ansi-white-intense-bg { background-color: #A1A6B2; }
.ansi-default-inverse-fg { color: #FFFFFF; }
.ansi-default-inverse-bg { background-color: #000000; }
.ansi-bold { font-weight: bold; }
.ansi-underline { text-decoration: underline; }
div.nbinput.container div.input_area div[class*=highlight] > pre,
div.nboutput.container div.output_area div[class*=highlight] > pre,
div.nboutput.container div.output_area div[class*=highlight].math,
div.nboutput.container div.output_area.rendered_html,
div.nboutput.container div.output_area > div.output_javascript,
div.nboutput.container div.output_area:not(.rendered_html) > img{
padding: 5px;
margin: 0;
}
/* fix copybtn overflow problem in chromium (needed for 'sphinx_copybutton') */
div.nbinput.container div.input_area > div[class^='highlight'],
div.nboutput.container div.output_area > div[class^='highlight']{
overflow-y: hidden;
}
/* hide copybtn icon on prompts (needed for 'sphinx_copybutton') */
.prompt .copybtn {
display: none;
}
/* Some additional styling taken form the Jupyter notebook CSS */
.jp-RenderedHTMLCommon table,
div.rendered_html table {
border: none;
border-collapse: collapse;
border-spacing: 0;
color: black;
font-size: 12px;
table-layout: fixed;
}
.jp-RenderedHTMLCommon thead,
div.rendered_html thead {
border-bottom: 1px solid black;
vertical-align: bottom;
}
.jp-RenderedHTMLCommon tr,
.jp-RenderedHTMLCommon th,
.jp-RenderedHTMLCommon td,
div.rendered_html tr,
div.rendered_html th,
div.rendered_html td {
text-align: right;
vertical-align: middle;
padding: 0.5em 0.5em;
line-height: normal;
white-space: normal;
max-width: none;
border: none;
}
.jp-RenderedHTMLCommon th,
div.rendered_html th {
font-weight: bold;
}
.jp-RenderedHTMLCommon tbody tr:nth-child(odd),
div.rendered_html tbody tr:nth-child(odd) {
background: #f5f5f5;
}
.jp-RenderedHTMLCommon tbody tr:hover,
div.rendered_html tbody tr:hover {
background: rgba(66, 165, 245, 0.2);
}
</style>
<div class="section" id="Feature-Extractors">
<h1><span class="section-number">3. </span>Feature Extractors<a class="headerlink" href="#Feature-Extractors" title="Permalink to this headline"></a></h1>
<div class="section" id="Feature-Extractors">
<h1><span class="section-number">6. </span>Feature Extractors<a class="headerlink" href="#Feature-Extractors" title="Permalink to this headline"></a></h1>
<p>In the previous page, we introduced <em>training data collectors</em>, which solve the optimization problem and collect raw training data, such as the optimal solution. In this page, we introduce <strong>feature extractors</strong>, which take the raw training data, stored in HDF5 files, and extract relevant information in order to train a machine learning model. We describe the extractors readily available in MIPLearn.</p>
<div class="section" id="Overview">
<h2><span class="section-number">3.1. </span>Overview<a class="headerlink" href="#Overview" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">6.1. </span>Overview<a class="headerlink" href="#Overview" title="Permalink to this headline"></a></h2>
<p>Feature extraction is an important step of the process of building a machine learning model because it helps to reduce the complexity of the data and convert it into a format that is more easily processed. Previous research has proposed converting absolute variable coefficients, for example, into relative values which are invariant to various transformations, such as problem scaling, making them more amenable to learning. Various other transformations have also been described.</p>
<p>In the framework, we treat data collection and feature extraction as two separate steps to accelerate the model development cycle. Specifically, collectors are typically time-consuming, as they often need to solve the problem to optimality, and therefore focus on collecting and storing all data that may or may not be relevant, in its raw format. Feature extractors, on the other hand, focus entirely on filtering the data and improving its representation, and are therefore much faster to run.
Experimenting with new data representations, therefore, can be done without resolving the instances.</p>
@ -506,13 +273,13 @@ Experimenting with new data representations, therefore, can be done without reso
subset of these methods, if it is known that it will not be used with a machine learning component that requires the other types of features.</p>
</div>
<div class="section" id="H5FieldsExtractor">
<h2><span class="section-number">3.2. </span>H5FieldsExtractor<a class="headerlink" href="#H5FieldsExtractor" title="Permalink to this headline"></a></h2>
<p><a class="reference external" href="#h5fieldsextractor">H5FieldsExtractor</a>, the most simple extractor in MIPLearn, simple extracts data that is already available in the HDF5 file, assembles it into a matrix and returns it as-is. The fields used to build instance, variable and constraint features are user-specified. The class also performs checks to ensure that the shapes of the returned matrices make sense.</p>
<h2><span class="section-number">6.2. </span>H5FieldsExtractor<a class="headerlink" href="#H5FieldsExtractor" title="Permalink to this headline"></a></h2>
<p><a class="reference internal" href="#H5FieldsExtractor"><span class="std std-ref">H5FieldsExtractor</span></a>, the most simple extractor in MIPLearn, simple extracts data that is already available in the HDF5 file, assembles it into a matrix and returns it as-is. The fields used to build instance, variable and constraint features are user-specified. The class also performs checks to ensure that the shapes of the returned matrices make sense.</p>
<div class="section" id="Example">
<h3>Example<a class="headerlink" href="#Example" title="Permalink to this headline"></a></h3>
<p>The example below demonstrates the usage of H5FieldsExtractor in a randomly generated instance of the multi-dimensional knapsack problem.</p>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[1]:
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[5]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">glob</span> <span class="kn">import</span> <span class="n">glob</span>
@ -522,12 +289,12 @@ subset of these methods, if it is known that it will not be used with a machine
<span class="kn">from</span> <span class="nn">scipy.stats</span> <span class="kn">import</span> <span class="n">uniform</span><span class="p">,</span> <span class="n">randint</span>
<span class="kn">from</span> <span class="nn">miplearn.collectors.basic</span> <span class="kn">import</span> <span class="n">BasicCollector</span>
<span class="kn">from</span> <span class="nn">miplearn.features.fields</span> <span class="kn">import</span> <span class="n">H5FieldsExtractor</span>
<span class="kn">from</span> <span class="nn">miplearn.extractors.fields</span> <span class="kn">import</span> <span class="n">H5FieldsExtractor</span>
<span class="kn">from</span> <span class="nn">miplearn.h5</span> <span class="kn">import</span> <span class="n">H5File</span>
<span class="kn">from</span> <span class="nn">miplearn.io</span> <span class="kn">import</span> <span class="n">save</span>
<span class="kn">from</span> <span class="nn">miplearn.io</span> <span class="kn">import</span> <span class="n">write_pkl_gz</span>
<span class="kn">from</span> <span class="nn">miplearn.problems.multiknapsack</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">MultiKnapsackGenerator</span><span class="p">,</span>
<span class="n">build_multiknapsack_model</span>
<span class="n">build_multiknapsack_model</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Set random seed to make example reproducible</span>
@ -535,7 +302,7 @@ subset of these methods, if it is known that it will not be used with a machine
<span class="c1"># Generate some random multiknapsack instances</span>
<span class="n">rmtree</span><span class="p">(</span><span class="s2">&quot;data/multiknapsack/&quot;</span><span class="p">,</span> <span class="n">ignore_errors</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">save</span><span class="p">(</span>
<span class="n">write_pkl_gz</span><span class="p">(</span>
<span class="n">MultiKnapsackGenerator</span><span class="p">(</span>
<span class="n">n</span><span class="o">=</span><span class="n">randint</span><span class="p">(</span><span class="n">low</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">high</span><span class="o">=</span><span class="mi">11</span><span class="p">),</span>
<span class="n">m</span><span class="o">=</span><span class="n">randint</span><span class="p">(</span><span class="n">low</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">high</span><span class="o">=</span><span class="mi">6</span><span class="p">),</span>
@ -547,7 +314,7 @@ subset of these methods, if it is known that it will not be used with a machine
<span class="n">p_jitter</span><span class="o">=</span><span class="n">uniform</span><span class="p">(</span><span class="n">loc</span><span class="o">=</span><span class="mf">0.75</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="mf">0.5</span><span class="p">),</span>
<span class="n">fix_w</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="p">)</span><span class="o">.</span><span class="n">generate</span><span class="p">(</span><span class="mi">10</span><span class="p">),</span>
<span class="s2">&quot;data/multiknapsack&quot;</span>
<span class="s2">&quot;data/multiknapsack&quot;</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Run the basic collector</span>
@ -578,7 +345,7 @@ subset of these methods, if it is known that it will not be used with a machine
<span class="s2">&quot;static_constr_rhs&quot;</span><span class="p">,</span>
<span class="s2">&quot;lp_constr_dual_values&quot;</span><span class="p">,</span>
<span class="s2">&quot;lp_constr_slacks&quot;</span><span class="p">,</span>
<span class="p">]</span>
<span class="p">],</span>
<span class="p">)</span>
<span class="k">with</span> <span class="n">H5File</span><span class="p">(</span><span class="s2">&quot;data/multiknapsack/00000.h5&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">h5</span><span class="p">:</span>
@ -631,16 +398,16 @@ constraint features (5, 3)
</div>
</div>
<div class="section" id="AlvLouWeh2017Extractor">
<h2><span class="section-number">3.3. </span>AlvLouWeh2017Extractor<a class="headerlink" href="#AlvLouWeh2017Extractor" title="Permalink to this headline"></a></h2>
<p>Alvarez, Louveaux and Wehenkel (2017) proposed a set features to describe a particular decision variable in a given node of the branch-and-bound tree, and applied it to the problem of mimicking strong branching decisions. The class <a class="reference external" href="#alvlouweh2017extractor">AlvLouWeh2017Extractor</a> implements a subset of these features (40 out of 64), which are available outside of the branch-and-bound tree. Some features are derived from the static defintion of the problem (i.e. from objective function and
<h2><span class="section-number">6.3. </span>AlvLouWeh2017Extractor<a class="headerlink" href="#AlvLouWeh2017Extractor" title="Permalink to this headline"></a></h2>
<p>Alvarez, Louveaux and Wehenkel (2017) proposed a set features to describe a particular decision variable in a given node of the branch-and-bound tree, and applied it to the problem of mimicking strong branching decisions. The class <a class="reference internal" href="#AlvLouWeh2017Extractor"><span class="std std-ref">AlvLouWeh2017Extractor</span></a> implements a subset of these features (40 out of 64), which are available outside of the branch-and-bound tree. Some features are derived from the static defintion of the problem (i.e. from objective function and
constraint data), while some features are derived from the solution to the LP relaxation. The features have been designed to be: (i) independent of the size of the problem; (ii) invariant with respect to irrelevant problem transformations, such as row and column permutation; and (iii) independent of the scale of the problem. We refer to the paper for a more complete description.</p>
<div class="section" id="id1">
<h3>Example<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[5]:
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[6]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">miplearn.features.AlvLouWeh2017</span> <span class="kn">import</span> <span class="n">AlvLouWeh2017Extractor</span>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">miplearn.extractors.AlvLouWeh2017</span> <span class="kn">import</span> <span class="n">AlvLouWeh2017Extractor</span>
<span class="kn">from</span> <span class="nn">miplearn.h5</span> <span class="kn">import</span> <span class="n">H5File</span>
<span class="c1"># Build the extractor</span>
@ -648,7 +415,6 @@ constraint data), while some features are derived from the solution to the LP re
<span class="c1"># Open previously-created multiknapsack training data</span>
<span class="k">with</span> <span class="n">H5File</span><span class="p">(</span><span class="s2">&quot;data/multiknapsack/00000.h5&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">h5</span><span class="p">:</span>
<span class="c1"># Extract and print variable features</span>
<span class="n">x1</span> <span class="o">=</span> <span class="n">ext</span><span class="o">.</span><span class="n">get_var_features</span><span class="p">(</span><span class="n">h5</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;x1&quot;</span><span class="p">,</span> <span class="n">x1</span><span class="o">.</span><span class="n">shape</span><span class="p">,</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">x1</span><span class="o">.</span><span class="n">round</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span>
@ -740,8 +506,8 @@ x1 (10, 40)
<div class='prev-next-bottom'>
<a class='left-prev' id="prev-link" href="../collectors/" title="previous page"><span class="section-number">2. </span>Training Data Collectors</a>
<a class='right-next' id="next-link" href="../primal/" title="next page"><span class="section-number">4. </span>Primal Components</a>
<a class='left-prev' id="prev-link" href="../collectors/" title="previous page"><span class="section-number">5. </span>Training Data Collectors</a>
<a class='right-next' id="next-link" href="../primal/" title="next page"><span class="section-number">7. </span>Primal Components</a>
</div>
@ -751,7 +517,7 @@ x1 (10, 40)
<div class="container">
<p>
&copy; Copyright 2020-2022, UChicago Argonne, LLC.<br/>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>

@ -60,14 +60,16 @@
},
{
"cell_type": "code",
"execution_count": 3,
"id": "94907996",
"execution_count": 1,
"id": "253adbf4",
"metadata": {
"collapsed": false
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"\n",
"from sklearn.dummy import DummyClassifier\n",
"from sklearn.neighbors import KNeighborsClassifier\n",
"\n",
@ -118,15 +120,13 @@
" extractor=H5FieldsExtractor(instance_fields=[\"static_var_obj_coeffs\"]),\n",
" constructor=MergeTopSolutions(k=3, thresholds=[0.25, 0.75]),\n",
" action=EnforceProximity(3),\n",
")"
")\n"
]
},
{
"cell_type": "markdown",
"id": "6b854305",
"metadata": {
"collapsed": false
},
"id": "f194a793",
"metadata": {},
"source": [
"## Independent vars primal component\n",
"\n",
@ -145,10 +145,13 @@
},
{
"cell_type": "code",
"execution_count": 4,
"id": "f5024983",
"execution_count": 2,
"id": "3fc0b5d1",
"metadata": {
"collapsed": false
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
@ -157,7 +160,6 @@
"from miplearn.classifiers.singleclass import SingleClassFix\n",
"from miplearn.components.primal.indep import IndependentVarsPrimalComponent\n",
"from miplearn.extractors.AlvLouWeh2017 import AlvLouWeh2017Extractor\n",
"from miplearn.solvers.learning import LearningSolver\n",
"from miplearn.components.primal.actions import SetWarmStart\n",
"\n",
"# Configures a primal component that independently predicts the value of each\n",
@ -173,15 +175,13 @@
" ),\n",
" extractor=AlvLouWeh2017Extractor(),\n",
" action=SetWarmStart(),\n",
")"
")\n"
]
},
{
"cell_type": "markdown",
"id": "dcb10079",
"metadata": {
"collapsed": false
},
"id": "45107a0c",
"metadata": {},
"source": [
"## Joint vars primal component\n",
"In the previous subsection, we used multiple machine learning models to independently predict the values of the binary decision variables. When these values are correlated, an alternative approach is to jointly predict the values of all binary variables using a single machine learning model. This strategy is implemented by `JointVarsPrimalComponent`. Compared to the previous ones, this component is much more straightforwad. It simply extracts instance features, using the user-provided feature extractor, then directly trains the user-provided binary classifier (using the `fit` method), without making any copies. The trained classifier is then used to predict entire solutions (using the `predict` method), which are given to the solver using one of the previously discussed methods. In the example below, we illustrate the usage of this component with a simple feed-forward neural network.\n",
@ -193,10 +193,13 @@
},
{
"cell_type": "code",
"execution_count": 5,
"id": "c98f7eb8",
"execution_count": 3,
"id": "cf9b52dd",
"metadata": {
"collapsed": false
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
@ -204,7 +207,6 @@
"from sklearn.neural_network import MLPClassifier\n",
"from miplearn.components.primal.joint import JointVarsPrimalComponent\n",
"from miplearn.extractors.fields import H5FieldsExtractor\n",
"from miplearn.solvers.learning import LearningSolver\n",
"from miplearn.components.primal.actions import SetWarmStart\n",
"\n",
"# Configures a primal component that uses a feedforward neural network\n",
@ -214,7 +216,7 @@
"comp = JointVarsPrimalComponent(\n",
" clf=MLPClassifier(),\n",
" extractor=H5FieldsExtractor(\n",
" instance_fields=['static_var_obj_coeffs'],\n",
" instance_fields=[\"static_var_obj_coeffs\"],\n",
" ),\n",
" action=SetWarmStart(),\n",
")\n",
@ -225,18 +227,16 @@
"comp = JointVarsPrimalComponent(\n",
" clf=ClassifierChain(SingleClassFix(LogisticRegression())),\n",
" extractor=H5FieldsExtractor(\n",
" instance_fields=['static_var_obj_coeffs'],\n",
" instance_fields=[\"static_var_obj_coeffs\"],\n",
" ),\n",
" action=SetWarmStart(),\n",
")"
")\n"
]
},
{
"cell_type": "markdown",
"id": "92461394",
"metadata": {
"collapsed": false
},
"id": "dddf7be4",
"metadata": {},
"source": [
"## Expert primal component\n",
"\n",
@ -248,9 +248,12 @@
{
"cell_type": "code",
"execution_count": 4,
"id": "fb7dbdd0",
"id": "9e2e81b9",
"metadata": {
"collapsed": false
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
@ -260,15 +263,13 @@
"# Configures an expert primal component, which reads a pre-computed\n",
"# optimal solution from the HDF5 file and provides it to the solver\n",
"# as warm start.\n",
"comp = ExpertPrimalComponent(\n",
" action=SetWarmStart()\n",
")"
"comp = ExpertPrimalComponent(action=SetWarmStart())\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@ -282,7 +283,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.13"
"version": "3.9.12"
}
},
"nbformat": 4,

@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>4. Primal Components &#8212; MIPLearn 0.3</title>
<title>7. Primal Components &#8212; MIPLearn 0.3</title>
<link href="../../_static/css/theme.css" rel="stylesheet" />
<link href="../../_static/css/index.c5995385ac14fb8791e8eb36b4908be2.css" rel="stylesheet" />
@ -24,6 +24,9 @@
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../_static/sphinx-book-theme.acff12b8f9c144ce68a297486a2fa670.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/custom.css" />
<link rel="preload" as="script" href="../../_static/js/index.1c5a1a01449ed65a7b51.js">
@ -38,8 +41,8 @@
<script type="text/x-mathjax-config">MathJax.Hub.Config({"tex2jax": {"inlineMath": [["\\(", "\\)"]], "displayMath": [["\\[", "\\]"]], "processRefs": false, "processEnvironments": false}})</script>
<link rel="index" title="Index" href="../../genindex/" />
<link rel="search" title="Search" href="../../search/" />
<link rel="next" title="5. Solvers" href="../solvers/" />
<link rel="prev" title="3. Feature Extractors" href="../features/" />
<link rel="next" title="8. Solvers" href="../solvers/" />
<link rel="prev" title="6. Feature Extractors" href="../features/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="docsearch:language" content="en" />
@ -68,6 +71,28 @@
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
@ -75,59 +100,59 @@
<ul class="current nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../problems/">
1. Benchmark Problems
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../collectors/">
2. Training Data Collectors
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../features/">
3. Feature Extractors
6. Feature Extractors
</a>
</li>
<li class="toctree-l1 current active">
<a class="current reference internal" href="#">
4. Primal Components
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../solvers/">
5. Solvers
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
API Reference
Python API Reference
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../api/problems/">
6. Benchmark Problems
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/collectors/">
7. Collectors &amp; Extractors
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/components/">
8. Components
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/solvers/">
9. Solvers
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/helpers/">
10. Helpers
13. Helpers
</a>
</li>
</ul>
@ -199,12 +224,12 @@
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Primal-component-actions">
4.1. Primal component actions
7.1. Primal component actions
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Memorizing-primal-component">
4.2. Memorizing primal component
7.2. Memorizing primal component
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -216,7 +241,7 @@
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Independent-vars-primal-component">
4.3. Independent vars primal component
7.3. Independent vars primal component
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -228,7 +253,7 @@
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Joint-vars-primal-component">
4.4. Joint vars primal component
7.4. Joint vars primal component
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -240,7 +265,7 @@
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Expert-primal-component">
4.5. Expert primal component
7.5. Expert primal component
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -261,270 +286,13 @@
<div>
<style>
/* CSS for nbsphinx extension */
/* remove conflicting styling from Sphinx themes */
div.nbinput.container div.prompt *,
div.nboutput.container div.prompt *,
div.nbinput.container div.input_area pre,
div.nboutput.container div.output_area pre,
div.nbinput.container div.input_area .highlight,
div.nboutput.container div.output_area .highlight {
border: none;
padding: 0;
margin: 0;
box-shadow: none;
}
div.nbinput.container > div[class*=highlight],
div.nboutput.container > div[class*=highlight] {
margin: 0;
}
div.nbinput.container div.prompt *,
div.nboutput.container div.prompt * {
background: none;
}
div.nboutput.container div.output_area .highlight,
div.nboutput.container div.output_area pre {
background: unset;
}
div.nboutput.container div.output_area div.highlight {
color: unset; /* override Pygments text color */
}
/* avoid gaps between output lines */
div.nboutput.container div[class*=highlight] pre {
line-height: normal;
}
/* input/output containers */
div.nbinput.container,
div.nboutput.container {
display: -webkit-flex;
display: flex;
align-items: flex-start;
margin: 0;
width: 100%;
}
@media (max-width: 540px) {
div.nbinput.container,
div.nboutput.container {
flex-direction: column;
}
}
/* input container */
div.nbinput.container {
padding-top: 5px;
}
/* last container */
div.nblast.container {
padding-bottom: 5px;
}
/* input prompt */
div.nbinput.container div.prompt pre {
color: #307FC1;
}
/* output prompt */
div.nboutput.container div.prompt pre {
color: #BF5B3D;
}
/* all prompts */
div.nbinput.container div.prompt,
div.nboutput.container div.prompt {
width: 4.5ex;
padding-top: 5px;
position: relative;
user-select: none;
}
div.nbinput.container div.prompt > div,
div.nboutput.container div.prompt > div {
position: absolute;
right: 0;
margin-right: 0.3ex;
}
@media (max-width: 540px) {
div.nbinput.container div.prompt,
div.nboutput.container div.prompt {
width: unset;
text-align: left;
padding: 0.4em;
}
div.nboutput.container div.prompt.empty {
padding: 0;
}
div.nbinput.container div.prompt > div,
div.nboutput.container div.prompt > div {
position: unset;
}
}
/* disable scrollbars and line breaks on prompts */
div.nbinput.container div.prompt pre,
div.nboutput.container div.prompt pre {
overflow: hidden;
white-space: pre;
}
/* input/output area */
div.nbinput.container div.input_area,
div.nboutput.container div.output_area {
-webkit-flex: 1;
flex: 1;
overflow: auto;
}
@media (max-width: 540px) {
div.nbinput.container div.input_area,
div.nboutput.container div.output_area {
width: 100%;
}
}
/* input area */
div.nbinput.container div.input_area {
border: 1px solid #e0e0e0;
border-radius: 2px;
/*background: #f5f5f5;*/
}
/* override MathJax center alignment in output cells */
div.nboutput.container div[class*=MathJax] {
text-align: left !important;
}
/* override sphinx.ext.imgmath center alignment in output cells */
div.nboutput.container div.math p {
text-align: left;
}
/* standard error */
div.nboutput.container div.output_area.stderr {
background: #fdd;
}
/* ANSI colors */
.ansi-black-fg { color: #3E424D; }
.ansi-black-bg { background-color: #3E424D; }
.ansi-black-intense-fg { color: #282C36; }
.ansi-black-intense-bg { background-color: #282C36; }
.ansi-red-fg { color: #E75C58; }
.ansi-red-bg { background-color: #E75C58; }
.ansi-red-intense-fg { color: #B22B31; }
.ansi-red-intense-bg { background-color: #B22B31; }
.ansi-green-fg { color: #00A250; }
.ansi-green-bg { background-color: #00A250; }
.ansi-green-intense-fg { color: #007427; }
.ansi-green-intense-bg { background-color: #007427; }
.ansi-yellow-fg { color: #DDB62B; }
.ansi-yellow-bg { background-color: #DDB62B; }
.ansi-yellow-intense-fg { color: #B27D12; }
.ansi-yellow-intense-bg { background-color: #B27D12; }
.ansi-blue-fg { color: #208FFB; }
.ansi-blue-bg { background-color: #208FFB; }
.ansi-blue-intense-fg { color: #0065CA; }
.ansi-blue-intense-bg { background-color: #0065CA; }
.ansi-magenta-fg { color: #D160C4; }
.ansi-magenta-bg { background-color: #D160C4; }
.ansi-magenta-intense-fg { color: #A03196; }
.ansi-magenta-intense-bg { background-color: #A03196; }
.ansi-cyan-fg { color: #60C6C8; }
.ansi-cyan-bg { background-color: #60C6C8; }
.ansi-cyan-intense-fg { color: #258F8F; }
.ansi-cyan-intense-bg { background-color: #258F8F; }
.ansi-white-fg { color: #C5C1B4; }
.ansi-white-bg { background-color: #C5C1B4; }
.ansi-white-intense-fg { color: #A1A6B2; }
.ansi-white-intense-bg { background-color: #A1A6B2; }
.ansi-default-inverse-fg { color: #FFFFFF; }
.ansi-default-inverse-bg { background-color: #000000; }
.ansi-bold { font-weight: bold; }
.ansi-underline { text-decoration: underline; }
div.nbinput.container div.input_area div[class*=highlight] > pre,
div.nboutput.container div.output_area div[class*=highlight] > pre,
div.nboutput.container div.output_area div[class*=highlight].math,
div.nboutput.container div.output_area.rendered_html,
div.nboutput.container div.output_area > div.output_javascript,
div.nboutput.container div.output_area:not(.rendered_html) > img{
padding: 5px;
margin: 0;
}
/* fix copybtn overflow problem in chromium (needed for 'sphinx_copybutton') */
div.nbinput.container div.input_area > div[class^='highlight'],
div.nboutput.container div.output_area > div[class^='highlight']{
overflow-y: hidden;
}
/* hide copybtn icon on prompts (needed for 'sphinx_copybutton') */
.prompt .copybtn {
display: none;
}
/* Some additional styling taken form the Jupyter notebook CSS */
.jp-RenderedHTMLCommon table,
div.rendered_html table {
border: none;
border-collapse: collapse;
border-spacing: 0;
color: black;
font-size: 12px;
table-layout: fixed;
}
.jp-RenderedHTMLCommon thead,
div.rendered_html thead {
border-bottom: 1px solid black;
vertical-align: bottom;
}
.jp-RenderedHTMLCommon tr,
.jp-RenderedHTMLCommon th,
.jp-RenderedHTMLCommon td,
div.rendered_html tr,
div.rendered_html th,
div.rendered_html td {
text-align: right;
vertical-align: middle;
padding: 0.5em 0.5em;
line-height: normal;
white-space: normal;
max-width: none;
border: none;
}
.jp-RenderedHTMLCommon th,
div.rendered_html th {
font-weight: bold;
}
.jp-RenderedHTMLCommon tbody tr:nth-child(odd),
div.rendered_html tbody tr:nth-child(odd) {
background: #f5f5f5;
}
.jp-RenderedHTMLCommon tbody tr:hover,
div.rendered_html tbody tr:hover {
background: rgba(66, 165, 245, 0.2);
}
</style>
<div class="section" id="Primal-Components">
<h1><span class="section-number">4. </span>Primal Components<a class="headerlink" href="#Primal-Components" title="Permalink to this headline"></a></h1>
<div class="section" id="Primal-Components">
<h1><span class="section-number">7. </span>Primal Components<a class="headerlink" href="#Primal-Components" title="Permalink to this headline"></a></h1>
<p>In MIPLearn, a <strong>primal component</strong> is class that uses machine learning to predict a (potentially partial) assignment of values to the decision variables of the problem. Predicting high-quality primal solutions may be beneficial, as they allow the MIP solver to prune potentially large portions of the search space. Alternatively, if proof of optimality is not required, the MIP solver can be used to complete the partial solution generated by the machine learning model and and double-check its
feasibility. MIPLearn allows both of these usage patterns.</p>
<p>In this page, we describe the four primal components currently included in MIPLearn, which employ machine learning in different ways. Each component is highly configurable, and accepts an user-provided machine learning model, which it uses for all predictions. Each component can also be configured to provide the solution to the solver in multiple ways, depending on whether proof of optimality is required.</p>
<div class="section" id="Primal-component-actions">
<h2><span class="section-number">4.1. </span>Primal component actions<a class="headerlink" href="#Primal-component-actions" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">7.1. </span>Primal component actions<a class="headerlink" href="#Primal-component-actions" title="Permalink to this headline"></a></h2>
<p>Before presenting the primal components themselves, we briefly discuss the three ways a solution may be provided to the solver. Each approach has benefits and limitations, which we also discuss in this section. All primal components can be configured to use any of the following approaches.</p>
<p>The first approach is to provide the solution to the solver as a <strong>warm start</strong>. This is implemented by the class <a class="reference external" href="SetWarmStart">SetWarmStart</a>. The main advantage is that this method maintains all optimality and feasibility guarantees of the MIP solver, while still providing significant performance benefits for various classes of problems. If the machine learning model is able to predict multiple solutions, it is also possible to set multiple warm starts. In this case, the solver evaluates
each warm start, discards the infeasible ones, then proceeds with the one that has the best objective value. The main disadvantage of this approach, compared to the next two, is that it provides relatively modest speedups for most problem classes, and no speedup at all for many others, even when the machine learning predictions are 100% accurate.</p>
@ -536,7 +304,7 @@ scratch. The main disadvantage of this approach is that it loses optimality guar
<p>to the problem, where <span class="math notranslate nohighlight">\(k\)</span> is a user-defined parameter, which indicates how many of the predicted variables are allowed to deviate from the machine learning suggestion. The main advantage of this approach, compared to fixing variables, is its tolerance to lower-quality machine learning predictions. Its main disadvantage is that it typically leads to smaller speedups, especially for larger values of <span class="math notranslate nohighlight">\(k\)</span>. This approach also loses optimality guarantees.</p>
</div>
<div class="section" id="Memorizing-primal-component">
<h2><span class="section-number">4.2. </span>Memorizing primal component<a class="headerlink" href="#Memorizing-primal-component" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">7.2. </span>Memorizing primal component<a class="headerlink" href="#Memorizing-primal-component" title="Permalink to this headline"></a></h2>
<p>A simple machine learning strategy for the prediction of primal solutions is to memorize all distinct solutions seen during training, then try to predict, during inference time, which of those memorized solutions are most likely to be feasible and to provide a good objective value for the current instance. The most promising solutions may alternatively be combined into a single partial solution, which is then provided to the MIP solver. Both variations of this strategy are implemented by the
<code class="docutils literal notranslate"><span class="pre">MemorizingPrimalComponent</span></code> class. Note that it is only applicable if the problem size, and in fact if the meaning of the decision variables, remains the same across problem instances.</p>
<p>More precisely, let <span class="math notranslate nohighlight">\(I_1,\ldots,I_n\)</span> be the training instances, and let <span class="math notranslate nohighlight">\(\bar{x}^1,\ldots,\bar{x}^n\)</span> be their respective optimal solutions. Given a new instance <span class="math notranslate nohighlight">\(I_{n+1}\)</span>, <code class="docutils literal notranslate"><span class="pre">MemorizingPrimalComponent</span></code> expects a user-provided binary classifier that assigns (through the <code class="docutils literal notranslate"><span class="pre">predict_proba</span></code> method, following scikit-learns conventions) a score <span class="math notranslate nohighlight">\(\delta_i\)</span> to each solution <span class="math notranslate nohighlight">\(\bar{x}^i\)</span>, such that solutions with higher score are more likely to be good solutions for
@ -558,15 +326,15 @@ Then it computes, for each binary decision variable <span class="math notranslat
</li>
</ol>
<p>The above specification of <code class="docutils literal notranslate"><span class="pre">MemorizingPrimalComponent</span></code> is meant to be as general as possible. Simpler strategies can be implemented by configuring this component in specific ways. For example, a simpler approach employed in the literature is to collect all optimal solutions, then provide the entire list of solutions to the solver as warm starts, without any filtering or post-processing. This strategy can be implemented with <code class="docutils literal notranslate"><span class="pre">MemorizingPrimalComponent</span></code> by using a model that returns a constant
value for all solutions (e.g. <a class="reference external" href="https://scikit-learn.org/stable/modules/generated/sklearn.dummy.DummyClassifier.html">scikit-learns DummyClassifier</a>), then selecting the top <span class="math notranslate nohighlight">\(n\)</span> (instead of <span class="math notranslate nohighlight">\(k\)</span>) solutions. See example below. Another simple approach is taking the solution to the most similar instance, and using it, by itself, as a warm start. This can be implemented by using a model that computes distances between the current instance and the training ones (e.g. <a class="reference external" href="https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html">scikit-learns
value for all solutions (e.g. <a class="reference external" href="https://scikit-learn.org/stable/modules/generated/sklearn.dummy.DummyClassifier.html">scikit-learns DummyClassifier</a>), then selecting the top <span class="math notranslate nohighlight">\(n\)</span> (instead of <span class="math notranslate nohighlight">\(k\)</span>) solutions. See example below. Another simple approach is taking the solution to the most similar instance, and using it, by itself, as a warm start. This can be implemented by using a model that computes distances between the current instance and the training ones (e.g. <a class="reference external" href="https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html">scikit-learns
KNeighborsClassifier</a>), then select the solution to the nearest one. See also example below. More complex strategies, of course, can also be configured.</p>
<div class="section" id="Examples">
<h3>Examples<a class="headerlink" href="#Examples" title="Permalink to this headline"></a></h3>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[3]:
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[1]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><br/><span></span><span class="kn">from</span> <span class="nn">sklearn.dummy</span> <span class="kn">import</span> <span class="n">DummyClassifier</span>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sklearn.dummy</span> <span class="kn">import</span> <span class="n">DummyClassifier</span>
<span class="kn">from</span> <span class="nn">sklearn.neighbors</span> <span class="kn">import</span> <span class="n">KNeighborsClassifier</span>
<span class="kn">from</span> <span class="nn">miplearn.components.primal.actions</span> <span class="kn">import</span> <span class="p">(</span>
@ -617,13 +385,13 @@ KNeighborsClassifier</a>), then select the solution to the nearest one. See also
<span class="n">constructor</span><span class="o">=</span><span class="n">MergeTopSolutions</span><span class="p">(</span><span class="n">k</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">thresholds</span><span class="o">=</span><span class="p">[</span><span class="mf">0.25</span><span class="p">,</span> <span class="mf">0.75</span><span class="p">]),</span>
<span class="n">action</span><span class="o">=</span><span class="n">EnforceProximity</span><span class="p">(</span><span class="mi">3</span><span class="p">),</span>
<span class="p">)</span>
</pre></div>
<br/></pre></div>
</div>
</div>
</div>
</div>
<div class="section" id="Independent-vars-primal-component">
<h2><span class="section-number">4.3. </span>Independent vars primal component<a class="headerlink" href="#Independent-vars-primal-component" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">7.3. </span>Independent vars primal component<a class="headerlink" href="#Independent-vars-primal-component" title="Permalink to this headline"></a></h2>
<p>Instead of memorizing previously-seen primal solutions, it is also natural to use machine learning models to directly predict the values of the decision variables, constructing a solution from scratch. This approach has the benefit of potentially constructing novel high-quality solutions, never observed in the training data. Two variations of this strategy are supported by MIPLearn: (i) predicting the values of the decision variables independently, using multiple ML models; or (ii) predicting
the values jointly, with a single model. We describe the first variation in this section, and the second variation in the next section.</p>
<p>Let <span class="math notranslate nohighlight">\(I_1,\ldots,I_n\)</span> be the training instances, and let <span class="math notranslate nohighlight">\(\bar{x}^1,\ldots,\bar{x}^n\)</span> be their respective optimal solutions. For each binary decision variable <span class="math notranslate nohighlight">\(x_j\)</span>, the component <code class="docutils literal notranslate"><span class="pre">IndependentVarsPrimalComponent</span></code> creates a copy of a user-provided binary classifier and trains it to predict the optimal value of <span class="math notranslate nohighlight">\(x_j\)</span>, given <span class="math notranslate nohighlight">\(\bar{x}^1_j,\ldots,\bar{x}^n_j\)</span> as training labels. The features provided to the model are the variable features computed by an user-provided
@ -638,7 +406,7 @@ probability of the value being zero or one (using the <code class="docutils lite
<div class="section" id="id1">
<h3>Examples<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[4]:
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[2]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sklearn.linear_model</span> <span class="kn">import</span> <span class="n">LogisticRegression</span>
@ -646,7 +414,6 @@ probability of the value being zero or one (using the <code class="docutils lite
<span class="kn">from</span> <span class="nn">miplearn.classifiers.singleclass</span> <span class="kn">import</span> <span class="n">SingleClassFix</span>
<span class="kn">from</span> <span class="nn">miplearn.components.primal.indep</span> <span class="kn">import</span> <span class="n">IndependentVarsPrimalComponent</span>
<span class="kn">from</span> <span class="nn">miplearn.extractors.AlvLouWeh2017</span> <span class="kn">import</span> <span class="n">AlvLouWeh2017Extractor</span>
<span class="kn">from</span> <span class="nn">miplearn.solvers.learning</span> <span class="kn">import</span> <span class="n">LearningSolver</span>
<span class="kn">from</span> <span class="nn">miplearn.components.primal.actions</span> <span class="kn">import</span> <span class="n">SetWarmStart</span>
<span class="c1"># Configures a primal component that independently predicts the value of each</span>
@ -663,13 +430,13 @@ probability of the value being zero or one (using the <code class="docutils lite
<span class="n">extractor</span><span class="o">=</span><span class="n">AlvLouWeh2017Extractor</span><span class="p">(),</span>
<span class="n">action</span><span class="o">=</span><span class="n">SetWarmStart</span><span class="p">(),</span>
<span class="p">)</span>
</pre></div>
<br/></pre></div>
</div>
</div>
</div>
</div>
<div class="section" id="Joint-vars-primal-component">
<h2><span class="section-number">4.4. </span>Joint vars primal component<a class="headerlink" href="#Joint-vars-primal-component" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">7.4. </span>Joint vars primal component<a class="headerlink" href="#Joint-vars-primal-component" title="Permalink to this headline"></a></h2>
<p>In the previous subsection, we used multiple machine learning models to independently predict the values of the binary decision variables. When these values are correlated, an alternative approach is to jointly predict the values of all binary variables using a single machine learning model. This strategy is implemented by <code class="docutils literal notranslate"><span class="pre">JointVarsPrimalComponent</span></code>. Compared to the previous ones, this component is much more straightforwad. It simply extracts instance features, using the user-provided feature
extractor, then directly trains the user-provided binary classifier (using the <code class="docutils literal notranslate"><span class="pre">fit</span></code> method), without making any copies. The trained classifier is then used to predict entire solutions (using the <code class="docutils literal notranslate"><span class="pre">predict</span></code> method), which are given to the solver using one of the previously discussed methods. In the example below, we illustrate the usage of this component with a simple feed-forward neural network.</p>
<p><code class="docutils literal notranslate"><span class="pre">JointVarsPrimalComponent</span></code> can also be used to implement strategies that use multiple machine learning models, but not indepedently. For example, a common strategy in multioutput prediction is building a <em>classifier chain</em>. In this approach, the first decision variable is predicted using the instance features alone; but the <span class="math notranslate nohighlight">\(n\)</span>-th decision variable is predicted using the instance features plus the predicted values of the <span class="math notranslate nohighlight">\(n-1\)</span> previous variables. This can be easily implemented
@ -677,14 +444,13 @@ using scikit-learns <code class="docutils literal notranslate"><span class="p
<div class="section" id="id2">
<h3>Examples<a class="headerlink" href="#id2" title="Permalink to this headline"></a></h3>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[5]:
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[3]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sklearn.multioutput</span> <span class="kn">import</span> <span class="n">ClassifierChain</span>
<span class="kn">from</span> <span class="nn">sklearn.neural_network</span> <span class="kn">import</span> <span class="n">MLPClassifier</span>
<span class="kn">from</span> <span class="nn">miplearn.components.primal.joint</span> <span class="kn">import</span> <span class="n">JointVarsPrimalComponent</span>
<span class="kn">from</span> <span class="nn">miplearn.extractors.fields</span> <span class="kn">import</span> <span class="n">H5FieldsExtractor</span>
<span class="kn">from</span> <span class="nn">miplearn.solvers.learning</span> <span class="kn">import</span> <span class="n">LearningSolver</span>
<span class="kn">from</span> <span class="nn">miplearn.components.primal.actions</span> <span class="kn">import</span> <span class="n">SetWarmStart</span>
<span class="c1"># Configures a primal component that uses a feedforward neural network</span>
@ -694,7 +460,7 @@ using scikit-learns <code class="docutils literal notranslate"><span class="p
<span class="n">comp</span> <span class="o">=</span> <span class="n">JointVarsPrimalComponent</span><span class="p">(</span>
<span class="n">clf</span><span class="o">=</span><span class="n">MLPClassifier</span><span class="p">(),</span>
<span class="n">extractor</span><span class="o">=</span><span class="n">H5FieldsExtractor</span><span class="p">(</span>
<span class="n">instance_fields</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;static_var_obj_coeffs&#39;</span><span class="p">],</span>
<span class="n">instance_fields</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;static_var_obj_coeffs&quot;</span><span class="p">],</span>
<span class="p">),</span>
<span class="n">action</span><span class="o">=</span><span class="n">SetWarmStart</span><span class="p">(),</span>
<span class="p">)</span>
@ -705,17 +471,17 @@ using scikit-learns <code class="docutils literal notranslate"><span class="p
<span class="n">comp</span> <span class="o">=</span> <span class="n">JointVarsPrimalComponent</span><span class="p">(</span>
<span class="n">clf</span><span class="o">=</span><span class="n">ClassifierChain</span><span class="p">(</span><span class="n">SingleClassFix</span><span class="p">(</span><span class="n">LogisticRegression</span><span class="p">())),</span>
<span class="n">extractor</span><span class="o">=</span><span class="n">H5FieldsExtractor</span><span class="p">(</span>
<span class="n">instance_fields</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;static_var_obj_coeffs&#39;</span><span class="p">],</span>
<span class="n">instance_fields</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;static_var_obj_coeffs&quot;</span><span class="p">],</span>
<span class="p">),</span>
<span class="n">action</span><span class="o">=</span><span class="n">SetWarmStart</span><span class="p">(),</span>
<span class="p">)</span>
</pre></div>
<br/></pre></div>
</div>
</div>
</div>
</div>
<div class="section" id="Expert-primal-component">
<h2><span class="section-number">4.5. </span>Expert primal component<a class="headerlink" href="#Expert-primal-component" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">7.5. </span>Expert primal component<a class="headerlink" href="#Expert-primal-component" title="Permalink to this headline"></a></h2>
<p>Before spending time and effort choosing a machine learning strategy and tweaking its parameters, it is usually a good idea to evaluate what would be the performance impact of the model if its predictions were 100% accurate. This is especially important for the prediction of warm starts, since they are not always very beneficial. To simplify this task, MIPLearn provides <code class="docutils literal notranslate"><span class="pre">ExpertPrimalComponent</span></code>, a component which simply loads the optimal solution from the HDF5 file, assuming that it has already
been computed, then directly provides it to the solver using one of the available methods. This component is useful in benchmarks, to evaluate how close to the best theoretical performance the machine learning components are.</p>
<div class="section" id="Example">
@ -730,10 +496,8 @@ been computed, then directly provides it to the solver using one of the availabl
<span class="c1"># Configures an expert primal component, which reads a pre-computed</span>
<span class="c1"># optimal solution from the HDF5 file and provides it to the solver</span>
<span class="c1"># as warm start.</span>
<span class="n">comp</span> <span class="o">=</span> <span class="n">ExpertPrimalComponent</span><span class="p">(</span>
<span class="n">action</span><span class="o">=</span><span class="n">SetWarmStart</span><span class="p">()</span>
<span class="p">)</span>
</pre></div>
<span class="n">comp</span> <span class="o">=</span> <span class="n">ExpertPrimalComponent</span><span class="p">(</span><span class="n">action</span><span class="o">=</span><span class="n">SetWarmStart</span><span class="p">())</span>
<br/></pre></div>
</div>
</div>
</div>
@ -746,8 +510,8 @@ been computed, then directly provides it to the solver using one of the availabl
<div class='prev-next-bottom'>
<a class='left-prev' id="prev-link" href="../features/" title="previous page"><span class="section-number">3. </span>Feature Extractors</a>
<a class='right-next' id="next-link" href="../solvers/" title="next page"><span class="section-number">5. </span>Solvers</a>
<a class='left-prev' id="prev-link" href="../features/" title="previous page"><span class="section-number">6. </span>Feature Extractors</a>
<a class='right-next' id="next-link" href="../solvers/" title="next page"><span class="section-number">8. </span>Solvers</a>
</div>
@ -757,7 +521,7 @@ been computed, then directly provides it to the solver using one of the availabl
<div class="container">
<p>
&copy; Copyright 2020-2022, UChicago Argonne, LLC.<br/>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>

@ -18,7 +18,7 @@
},
{
"cell_type": "markdown",
"id": "fbfe86db",
"id": "1ba30e52",
"metadata": {
"collapsed": false
},
@ -64,7 +64,7 @@
},
{
"cell_type": "markdown",
"id": "0dcc6210",
"id": "218add9f",
"metadata": {
"collapsed": false
},
@ -85,7 +85,7 @@
},
{
"cell_type": "markdown",
"id": "3e09abef",
"id": "3ffe5c46",
"metadata": {
"collapsed": false
},
@ -103,7 +103,7 @@
},
{
"cell_type": "markdown",
"id": "c48da99f",
"id": "fd6cb059",
"metadata": {
"collapsed": false
},
@ -134,9 +134,11 @@
"8 [ 8.47 21.9 16.58 15.37 3.76 3.91 1.57 20.57 14.76 18.61] 94.58\n",
"9 [ 8.57 22.77 17.06 16.25 4.14 4. 1.56 22.97 14.09 19.09] 100.79\n",
"\n",
"Restricted license - for non-production use only - expires 2023-10-25\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 20 rows, 110 columns and 210 nonzeros\n",
"Model fingerprint: 0x1ff9913f\n",
"Variable types: 0 continuous, 110 integer (110 binary)\n",
@ -160,7 +162,7 @@
"H 0 0 2.0000000 1.27484 36.3% - 0s\n",
" 0 0 1.27484 0 4 2.00000 1.27484 36.3% - 0s\n",
"\n",
"Explored 1 nodes (38 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Explored 1 nodes (38 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 3: 2 4 5 \n",
@ -168,6 +170,14 @@
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 2.000000000000e+00, best bound 2.000000000000e+00, gap 0.0000%\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/axavier/.conda/envs/miplearn2/lib/python3.9/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n"
]
}
],
"source": [
@ -195,7 +205,7 @@
"\n",
"# Optimize first instance\n",
"model = build_binpack_model(data[0])\n",
"model.optimize()"
"model.optimize()\n"
]
},
{
@ -224,7 +234,7 @@
},
{
"cell_type": "markdown",
"id": "021bbcef",
"id": "307ab9bf",
"metadata": {
"collapsed": false
},
@ -294,7 +304,7 @@
},
{
"cell_type": "markdown",
"id": "bfcb9910",
"id": "5caf77ba",
"metadata": {
"collapsed": false
},
@ -323,8 +333,11 @@
"capacities\n",
" [1310. 988. 1004. 1269. 1007.]\n",
"\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 5 rows, 10 columns and 50 nonzeros\n",
"Model fingerprint: 0xaf3ac15e\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n",
@ -350,7 +363,7 @@
"Cutting planes:\n",
" Cover: 1\n",
"\n",
"Explored 1 nodes (4 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Explored 1 nodes (4 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 2: -1279 -804 \n",
@ -394,7 +407,7 @@
"\n",
"# Build model and optimize\n",
"model = build_multiknapsack_model(data[0])\n",
"model.optimize()"
"model.optimize()\n"
]
},
{
@ -459,7 +472,7 @@
},
{
"cell_type": "markdown",
"id": "f58d88e5",
"id": "838ef9d8",
"metadata": {
"collapsed": false
},
@ -492,8 +505,11 @@
"demands = [6.12 1.39 2.92 3.66 4.56 7.85 2. 5.14 5.92 0.46]\n",
"capacities = [151.89 42.63 16.26 237.22 241.41 202.1 76.15 24.42 171.06 110.04]\n",
"\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 21 rows, 110 columns and 220 nonzeros\n",
"Model fingerprint: 0x8d8d9346\n",
"Variable types: 0 continuous, 110 integer (110 binary)\n",
@ -526,7 +542,7 @@
" 0 0 86.06884 0 15 93.92000 86.06884 8.36% - 0s\n",
"* 0 0 0 91.2300000 91.23000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (60 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Explored 1 nodes (70 simplex iterations) in 0.02 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 10: 91.23 93.92 93.98 ... 368.79\n",
@ -568,7 +584,7 @@
"\n",
"# Build and optimize model\n",
"model = build_pmedian_model(data[0])\n",
"model.optimize()"
"model.optimize()\n"
]
},
{
@ -583,7 +599,7 @@
},
{
"cell_type": "markdown",
"id": "5e02b717",
"id": "96a26e2d",
"metadata": {
"collapsed": false
},
@ -658,8 +674,11 @@
"costs [1044.58 850.13 1014.5 944.83 697.9 971.87 213.49 220.98 70.23\n",
" 425.33]\n",
"\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 5 rows, 10 columns and 28 nonzeros\n",
"Model fingerprint: 0xe5c2d4fa\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n",
@ -686,7 +705,7 @@
"source": [
"import numpy as np\n",
"from scipy.stats import uniform, randint\n",
"from miplearn.problems.setcover import SetCoverGenerator, build_setcover_model\n",
"from miplearn.problems.setcover import SetCoverGenerator, build_setcover_model_gurobipy\n",
"\n",
"# Set random seed, to make example reproducible\n",
"np.random.seed(42)\n",
@ -710,8 +729,8 @@
"print()\n",
"\n",
"# Build and optimize model\n",
"model = build_setcover_model(data[0])\n",
"model.optimize()"
"model = build_setcover_model_gurobipy(data[0])\n",
"model.optimize()\n"
]
},
{
@ -726,7 +745,7 @@
},
{
"cell_type": "markdown",
"id": "fe2d24e5",
"id": "7c5d228d",
"metadata": {
"collapsed": false
},
@ -738,7 +757,7 @@
},
{
"cell_type": "markdown",
"id": "679ae3f5",
"id": "7361cea0",
"metadata": {
"collapsed": false
},
@ -757,7 +776,7 @@
},
{
"cell_type": "markdown",
"id": "66306263",
"id": "c32306f4",
"metadata": {
"collapsed": false
},
@ -775,7 +794,7 @@
{
"cell_type": "code",
"execution_count": 5,
"id": "9d0ee846",
"id": "4607dbda",
"metadata": {
"collapsed": false
},
@ -793,8 +812,11 @@
"costs [1044.58 850.13 1014.5 944.83 697.9 971.87 213.49 220.98 70.23\n",
" 425.33]\n",
"\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 5 rows, 10 columns and 28 nonzeros\n",
"Model fingerprint: 0x4ee91388\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n",
@ -847,7 +869,7 @@
"\n",
"# Build and optimize model\n",
"model = build_setpack_model(data[0])\n",
"model.optimize()"
"model.optimize()\n"
]
},
{
@ -866,7 +888,7 @@
},
{
"cell_type": "markdown",
"id": "31bc4be9",
"id": "93235cdd",
"metadata": {
"collapsed": false
},
@ -883,7 +905,7 @@
},
{
"cell_type": "markdown",
"id": "135f311f",
"id": "90b9e623",
"metadata": {
"collapsed": false
},
@ -902,7 +924,7 @@
},
{
"cell_type": "code",
"execution_count": 24,
"execution_count": 6,
"id": "0f996e99-0ec9-472b-be8a-30c9b8556931",
"metadata": {},
"outputs": [
@ -914,8 +936,11 @@
"weights[0] [37.45 95.07 73.2 59.87 15.6 15.6 5.81 86.62 60.11 70.81]\n",
"weights[1] [ 2.06 96.99 83.24 21.23 18.18 18.34 30.42 52.48 43.19 29.12]\n",
"\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 10 rows, 10 columns and 24 nonzeros\n",
"Model fingerprint: 0xf4c21689\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n",
@ -937,7 +962,7 @@
"\n",
" 0 0 infeasible 0 -219.14000 -219.14000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (4 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Explored 1 nodes (4 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 1: -219.14 \n",
@ -952,7 +977,10 @@
"import random\n",
"import numpy as np\n",
"from scipy.stats import uniform, randint\n",
"from miplearn.problems.stab import MaxWeightStableSetGenerator, build_stab_model\n",
"from miplearn.problems.stab import (\n",
" MaxWeightStableSetGenerator,\n",
" build_stab_model_gurobipy,\n",
")\n",
"\n",
"# Set random seed to make example reproducible\n",
"random.seed(42)\n",
@ -974,8 +1002,8 @@
"print()\n",
"\n",
"# Load and optimize the first instance\n",
"model = build_stab_model(data[0])\n",
"model.optimize()"
"model = build_stab_model_gurobipy(data[0])\n",
"model.optimize()\n"
]
},
{
@ -990,7 +1018,7 @@
},
{
"cell_type": "markdown",
"id": "4074551b",
"id": "aa307ff0",
"metadata": {
"collapsed": false
},
@ -1002,7 +1030,7 @@
},
{
"cell_type": "markdown",
"id": "5672fbab",
"id": "a5436195",
"metadata": {
"collapsed": false
},
@ -1022,7 +1050,7 @@
},
{
"cell_type": "markdown",
"id": "257111e2",
"id": "df26c9f5",
"metadata": {
"collapsed": false
},
@ -1042,7 +1070,7 @@
},
{
"cell_type": "markdown",
"id": "3c20e302",
"id": "0fd000fe",
"metadata": {
"collapsed": false
},
@ -1052,8 +1080,8 @@
},
{
"cell_type": "code",
"execution_count": 32,
"id": "e08346b5",
"execution_count": 7,
"id": "6ee78519",
"metadata": {
"collapsed": false
},
@ -1086,8 +1114,11 @@
" [ 668. 446. 317. 648. 469. 752. 394. 286. 274. 0.]]\n",
"\n",
"Set parameter LazyConstraints to value 1\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 10 rows, 45 columns and 90 nonzeros\n",
"Model fingerprint: 0x719675e5\n",
"Variable types: 0 continuous, 45 integer (45 binary)\n",
@ -1118,7 +1149,7 @@
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 2.921000000000e+03, best bound 2.921000000000e+03, gap 0.0000%\n",
"\n",
"User-callback calls 100, time in user-callback 0.00 sec\n"
"User-callback calls 106, time in user-callback 0.00 sec\n"
]
}
],
@ -1150,7 +1181,7 @@
"\n",
"# Load and optimize the first instance\n",
"model = build_tsp_model(data[0])\n",
"model.optimize()"
"model.optimize()\n"
]
},
{
@ -1165,7 +1196,7 @@
},
{
"cell_type": "markdown",
"id": "b18b10c9",
"id": "fd30f83e",
"metadata": {
"collapsed": false
},
@ -1184,7 +1215,7 @@
},
{
"cell_type": "markdown",
"id": "12739207",
"id": "1da000b8",
"metadata": {
"collapsed": false
},
@ -1220,7 +1251,7 @@
},
{
"cell_type": "markdown",
"id": "b5d85554",
"id": "721f7b0c",
"metadata": {
"collapsed": false
},
@ -1237,7 +1268,7 @@
},
{
"cell_type": "markdown",
"id": "a2f9e098",
"id": "f49a5e24",
"metadata": {
"collapsed": false
},
@ -1256,7 +1287,7 @@
},
{
"cell_type": "markdown",
"id": "09e98292",
"id": "cae4f51a",
"metadata": {
"collapsed": false
},
@ -1267,7 +1298,7 @@
{
"cell_type": "code",
"execution_count": 8,
"id": "e7c16609",
"id": "2d7295e0",
"metadata": {
"collapsed": false
},
@ -1302,8 +1333,11 @@
" 828.28 775.18 834.99 959.76 865.72 1193.52 1058.92 985.19 893.92\n",
" 962.16 781.88 723.15 639.04 602.4 787.02]\n",
"\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 578 rows, 360 columns and 2128 nonzeros\n",
"Model fingerprint: 0x4dc1c661\n",
"Variable types: 120 continuous, 240 integer (240 binary)\n",
@ -1313,22 +1347,22 @@
" Bounds range [1e+00, 1e+00]\n",
" RHS range [1e+00, 1e+03]\n",
"Presolve removed 244 rows and 131 columns\n",
"Presolve time: 0.01s\n",
"Presolve time: 0.02s\n",
"Presolved: 334 rows, 229 columns, 842 nonzeros\n",
"Variable types: 116 continuous, 113 integer (113 binary)\n",
"Found heuristic solution: objective 441426.66550\n",
"Found heuristic solution: objective 440662.46430\n",
"Found heuristic solution: objective 429461.97680\n",
"Found heuristic solution: objective 374043.64040\n",
"\n",
"Root relaxation: objective 3.361348e+05, 139 iterations, 0.00 seconds (0.00 work units)\n",
"Root relaxation: objective 3.361348e+05, 142 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 336134.820 0 18 374043.640 336134.820 10.1% - 0s\n",
"H 0 0 368600.14450 336134.820 8.81% - 0s\n",
"H 0 0 364721.76610 364721.766 0.00% - 0s\n",
" 0 0 - 0 364721.766 364721.766 0.00% - 0s\n",
"H 0 0 364721.76610 336134.820 7.84% - 0s\n",
" 0 0 cutoff 0 364721.766 364721.766 0.00% - 0s\n",
"\n",
"Cutting planes:\n",
" Gomory: 3\n",
@ -1340,10 +1374,10 @@
" RLT: 1\n",
" Relax-and-lift: 7\n",
"\n",
"Explored 1 nodes (232 simplex iterations) in 0.04 seconds (0.02 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Explored 1 nodes (234 simplex iterations) in 0.04 seconds (0.02 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 5: 364722 368600 374044 ... 441427\n",
"Solution count 5: 364722 368600 374044 ... 440662\n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 3.647217661000e+05, best bound 3.647217661000e+05, gap 0.0000%\n"
@ -1391,7 +1425,7 @@
"\n",
"# Load and optimize the first instance\n",
"model = build_uc_model(data[0])\n",
"model.optimize()"
"model.optimize()\n"
]
},
{
@ -1406,7 +1440,7 @@
},
{
"cell_type": "markdown",
"id": "238e9968",
"id": "09ba5ccf",
"metadata": {
"collapsed": false
},
@ -1419,7 +1453,7 @@
},
{
"cell_type": "markdown",
"id": "d1f1cced",
"id": "c72baa43",
"metadata": {
"collapsed": false
},
@ -1438,7 +1472,7 @@
},
{
"cell_type": "markdown",
"id": "cbcb1ae0",
"id": "43bb19ae",
"metadata": {
"collapsed": false
},
@ -1467,8 +1501,11 @@
"weights[0] [37.45 95.07 73.2 59.87 15.6 15.6 5.81 86.62 60.11 70.81]\n",
"weights[1] [ 2.06 96.99 83.24 21.23 18.18 18.34 30.42 52.48 43.19 29.12]\n",
"\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 15 rows, 10 columns and 30 nonzeros\n",
"Model fingerprint: 0x2d2d1390\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n",
@ -1491,7 +1528,7 @@
" 0 0 infeasible 0 301.00000 301.00000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (8 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 1: 301 \n",
"\n",
@ -1504,7 +1541,10 @@
"import random\n",
"import numpy as np\n",
"from scipy.stats import uniform, randint\n",
"from miplearn.problems.vertexcover import MinWeightVertexCoverGenerator, build_vertexcover_model\n",
"from miplearn.problems.vertexcover import (\n",
" MinWeightVertexCoverGenerator,\n",
" build_vertexcover_model,\n",
")\n",
"\n",
"# Set random seed to make example reproducible\n",
"random.seed(42)\n",
@ -1533,7 +1573,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "d1d25734",
"id": "c0a76d28",
"metadata": {
"collapsed": false
},
@ -1557,7 +1597,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.13"
"version": "3.9.12"
}
},
"nbformat": 4,

@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>1. Benchmark Problems &#8212; MIPLearn 0.3</title>
<title>4. Benchmark Problems &#8212; MIPLearn 0.3</title>
<link href="../../_static/css/theme.css" rel="stylesheet" />
<link href="../../_static/css/index.c5995385ac14fb8791e8eb36b4908be2.css" rel="stylesheet" />
@ -24,6 +24,10 @@
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../_static/sphinx-book-theme.acff12b8f9c144ce68a297486a2fa670.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/custom.css" />
<link rel="preload" as="script" href="../../_static/js/index.1c5a1a01449ed65a7b51.js">
@ -38,8 +42,8 @@
<script type="text/x-mathjax-config">MathJax.Hub.Config({"tex2jax": {"inlineMath": [["\\(", "\\)"]], "displayMath": [["\\[", "\\]"]], "processRefs": false, "processEnvironments": false}})</script>
<link rel="index" title="Index" href="../../genindex/" />
<link rel="search" title="Search" href="../../search/" />
<link rel="next" title="2. Training Data Collectors" href="../collectors/" />
<link rel="prev" title="MIPLearn" href="../../" />
<link rel="next" title="5. Training Data Collectors" href="../collectors/" />
<link rel="prev" title="3. Getting started (JuMP)" href="../../tutorials/getting-started-jump/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="docsearch:language" content="en" />
@ -68,6 +72,28 @@
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
@ -75,59 +101,59 @@
<ul class="current nav bd-sidenav">
<li class="toctree-l1 current active">
<a class="current reference internal" href="#">
1. Benchmark Problems
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../collectors/">
2. Training Data Collectors
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../features/">
3. Feature Extractors
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../primal/">
4. Primal Components
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../solvers/">
5. Solvers
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
API Reference
Python API Reference
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../api/problems/">
6. Benchmark Problems
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/collectors/">
7. Collectors &amp; Extractors
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/components/">
8. Components
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/solvers/">
9. Solvers
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/helpers/">
10. Helpers
13. Helpers
</a>
</li>
</ul>
@ -199,12 +225,12 @@
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Overview">
1.1. Overview
4.1. Overview
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Bin-Packing">
1.2. Bin Packing
4.2. Bin Packing
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -226,7 +252,7 @@
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Multi-Dimensional-Knapsack">
1.3. Multi-Dimensional Knapsack
4.3. Multi-Dimensional Knapsack
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -248,7 +274,7 @@
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Capacitated-P-Median">
1.4. Capacitated P-Median
4.4. Capacitated P-Median
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -270,7 +296,7 @@
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Set-cover">
1.5. Set cover
4.5. Set cover
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -292,7 +318,7 @@
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Set-Packing">
1.6. Set Packing
4.6. Set Packing
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -314,7 +340,7 @@
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Stable-Set">
1.7. Stable Set
4.7. Stable Set
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -336,7 +362,7 @@
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Traveling-Salesman">
1.8. Traveling Salesman
4.8. Traveling Salesman
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -358,7 +384,7 @@
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Unit-Commitment">
1.9. Unit Commitment
4.9. Unit Commitment
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -380,7 +406,7 @@
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Vertex-Cover">
1.10. Vertex Cover
4.10. Vertex Cover
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -411,267 +437,10 @@
<div>
<style>
/* CSS for nbsphinx extension */
/* remove conflicting styling from Sphinx themes */
div.nbinput.container div.prompt *,
div.nboutput.container div.prompt *,
div.nbinput.container div.input_area pre,
div.nboutput.container div.output_area pre,
div.nbinput.container div.input_area .highlight,
div.nboutput.container div.output_area .highlight {
border: none;
padding: 0;
margin: 0;
box-shadow: none;
}
div.nbinput.container > div[class*=highlight],
div.nboutput.container > div[class*=highlight] {
margin: 0;
}
div.nbinput.container div.prompt *,
div.nboutput.container div.prompt * {
background: none;
}
div.nboutput.container div.output_area .highlight,
div.nboutput.container div.output_area pre {
background: unset;
}
div.nboutput.container div.output_area div.highlight {
color: unset; /* override Pygments text color */
}
/* avoid gaps between output lines */
div.nboutput.container div[class*=highlight] pre {
line-height: normal;
}
/* input/output containers */
div.nbinput.container,
div.nboutput.container {
display: -webkit-flex;
display: flex;
align-items: flex-start;
margin: 0;
width: 100%;
}
@media (max-width: 540px) {
div.nbinput.container,
div.nboutput.container {
flex-direction: column;
}
}
/* input container */
div.nbinput.container {
padding-top: 5px;
}
/* last container */
div.nblast.container {
padding-bottom: 5px;
}
/* input prompt */
div.nbinput.container div.prompt pre {
color: #307FC1;
}
/* output prompt */
div.nboutput.container div.prompt pre {
color: #BF5B3D;
}
/* all prompts */
div.nbinput.container div.prompt,
div.nboutput.container div.prompt {
width: 4.5ex;
padding-top: 5px;
position: relative;
user-select: none;
}
div.nbinput.container div.prompt > div,
div.nboutput.container div.prompt > div {
position: absolute;
right: 0;
margin-right: 0.3ex;
}
@media (max-width: 540px) {
div.nbinput.container div.prompt,
div.nboutput.container div.prompt {
width: unset;
text-align: left;
padding: 0.4em;
}
div.nboutput.container div.prompt.empty {
padding: 0;
}
div.nbinput.container div.prompt > div,
div.nboutput.container div.prompt > div {
position: unset;
}
}
/* disable scrollbars and line breaks on prompts */
div.nbinput.container div.prompt pre,
div.nboutput.container div.prompt pre {
overflow: hidden;
white-space: pre;
}
/* input/output area */
div.nbinput.container div.input_area,
div.nboutput.container div.output_area {
-webkit-flex: 1;
flex: 1;
overflow: auto;
}
@media (max-width: 540px) {
div.nbinput.container div.input_area,
div.nboutput.container div.output_area {
width: 100%;
}
}
/* input area */
div.nbinput.container div.input_area {
border: 1px solid #e0e0e0;
border-radius: 2px;
/*background: #f5f5f5;*/
}
/* override MathJax center alignment in output cells */
div.nboutput.container div[class*=MathJax] {
text-align: left !important;
}
/* override sphinx.ext.imgmath center alignment in output cells */
div.nboutput.container div.math p {
text-align: left;
}
/* standard error */
div.nboutput.container div.output_area.stderr {
background: #fdd;
}
/* ANSI colors */
.ansi-black-fg { color: #3E424D; }
.ansi-black-bg { background-color: #3E424D; }
.ansi-black-intense-fg { color: #282C36; }
.ansi-black-intense-bg { background-color: #282C36; }
.ansi-red-fg { color: #E75C58; }
.ansi-red-bg { background-color: #E75C58; }
.ansi-red-intense-fg { color: #B22B31; }
.ansi-red-intense-bg { background-color: #B22B31; }
.ansi-green-fg { color: #00A250; }
.ansi-green-bg { background-color: #00A250; }
.ansi-green-intense-fg { color: #007427; }
.ansi-green-intense-bg { background-color: #007427; }
.ansi-yellow-fg { color: #DDB62B; }
.ansi-yellow-bg { background-color: #DDB62B; }
.ansi-yellow-intense-fg { color: #B27D12; }
.ansi-yellow-intense-bg { background-color: #B27D12; }
.ansi-blue-fg { color: #208FFB; }
.ansi-blue-bg { background-color: #208FFB; }
.ansi-blue-intense-fg { color: #0065CA; }
.ansi-blue-intense-bg { background-color: #0065CA; }
.ansi-magenta-fg { color: #D160C4; }
.ansi-magenta-bg { background-color: #D160C4; }
.ansi-magenta-intense-fg { color: #A03196; }
.ansi-magenta-intense-bg { background-color: #A03196; }
.ansi-cyan-fg { color: #60C6C8; }
.ansi-cyan-bg { background-color: #60C6C8; }
.ansi-cyan-intense-fg { color: #258F8F; }
.ansi-cyan-intense-bg { background-color: #258F8F; }
.ansi-white-fg { color: #C5C1B4; }
.ansi-white-bg { background-color: #C5C1B4; }
.ansi-white-intense-fg { color: #A1A6B2; }
.ansi-white-intense-bg { background-color: #A1A6B2; }
.ansi-default-inverse-fg { color: #FFFFFF; }
.ansi-default-inverse-bg { background-color: #000000; }
.ansi-bold { font-weight: bold; }
.ansi-underline { text-decoration: underline; }
div.nbinput.container div.input_area div[class*=highlight] > pre,
div.nboutput.container div.output_area div[class*=highlight] > pre,
div.nboutput.container div.output_area div[class*=highlight].math,
div.nboutput.container div.output_area.rendered_html,
div.nboutput.container div.output_area > div.output_javascript,
div.nboutput.container div.output_area:not(.rendered_html) > img{
padding: 5px;
margin: 0;
}
/* fix copybtn overflow problem in chromium (needed for 'sphinx_copybutton') */
div.nbinput.container div.input_area > div[class^='highlight'],
div.nboutput.container div.output_area > div[class^='highlight']{
overflow-y: hidden;
}
/* hide copybtn icon on prompts (needed for 'sphinx_copybutton') */
.prompt .copybtn {
display: none;
}
/* Some additional styling taken form the Jupyter notebook CSS */
.jp-RenderedHTMLCommon table,
div.rendered_html table {
border: none;
border-collapse: collapse;
border-spacing: 0;
color: black;
font-size: 12px;
table-layout: fixed;
}
.jp-RenderedHTMLCommon thead,
div.rendered_html thead {
border-bottom: 1px solid black;
vertical-align: bottom;
}
.jp-RenderedHTMLCommon tr,
.jp-RenderedHTMLCommon th,
.jp-RenderedHTMLCommon td,
div.rendered_html tr,
div.rendered_html th,
div.rendered_html td {
text-align: right;
vertical-align: middle;
padding: 0.5em 0.5em;
line-height: normal;
white-space: normal;
max-width: none;
border: none;
}
.jp-RenderedHTMLCommon th,
div.rendered_html th {
font-weight: bold;
}
.jp-RenderedHTMLCommon tbody tr:nth-child(odd),
div.rendered_html tbody tr:nth-child(odd) {
background: #f5f5f5;
}
.jp-RenderedHTMLCommon tbody tr:hover,
div.rendered_html tbody tr:hover {
background: rgba(66, 165, 245, 0.2);
}
</style>
<div class="section" id="Benchmark-Problems">
<h1><span class="section-number">1. </span>Benchmark Problems<a class="headerlink" href="#Benchmark-Problems" title="Permalink to this headline"></a></h1>
<div class="section" id="Benchmark-Problems">
<h1><span class="section-number">4. </span>Benchmark Problems<a class="headerlink" href="#Benchmark-Problems" title="Permalink to this headline"></a></h1>
<div class="section" id="Overview">
<h2><span class="section-number">1.1. </span>Overview<a class="headerlink" href="#Overview" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">4.1. </span>Overview<a class="headerlink" href="#Overview" title="Permalink to this headline"></a></h2>
<p>Benchmark sets such as <a class="reference external" href="https://miplib.zib.de/">MIPLIB</a> or <a class="reference external" href="http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/">TSPLIB</a> are usually employed to evaluate the performance of conventional MIP solvers. Two shortcomings, unfortunately, make existing benchmark sets less than ideal for evaluating the performance of learning-enhanced MIP solvers: (i) while existing benchmark sets typically contain hundreds or thousands of instances, machine learning (ML) methods typically benefit from having
orders of magnitude more instances available for training; (ii) current machine learning methods typically provide best performance on sets of homogeneous instances, buch general-purpose benchmark sets contain relatively few examples of each problem type.</p>
<p>To tackle this challenge, MIPLearn provides random instance generators for a wide variety of classical optimization problems, covering applications from different fields, that can be used to evaluate new learning-enhanced MIP techniques in a measurable and reproducible way. As of MIPLearn 0.3, nine problem generators are available, each customizable with user-provided probability distribution and flexible parameters. The generators can be configured, for example, to produce large sets of very
@ -690,7 +459,7 @@ similar instances of same size, where only the objective function changes, or mo
</div>
</div>
<div class="section" id="Bin-Packing">
<h2><span class="section-number">1.2. </span>Bin Packing<a class="headerlink" href="#Bin-Packing" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">4.2. </span>Bin Packing<a class="headerlink" href="#Bin-Packing" title="Permalink to this headline"></a></h2>
<p><strong>Bin packing</strong> is a combinatorial optimization problem that asks for the optimal way to pack a given set of items into a finite number of containers (or bins) of fixed capacity. More specifically, the problem is to assign indivisible items of different sizes to identical bins, while minimizing the number of bins used. The problem is NP-hard and has many practical applications, including logistics and warehouse management, where it is used to determine how to best store and transport goods using
a limited amount of space.</p>
<div class="section" id="Formulation">
@ -745,10 +514,10 @@ a limited amount of space.</p>
<span class="c1"># Optimize first instance</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">build_binpack_model</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">model</span><span class="o">.</span><span class="n">optimize</span><span class="p">()</span>
</pre></div>
<br/></pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
<div class="nboutput docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area docutils container">
@ -764,9 +533,11 @@ a limited amount of space.</p>
8 [ 8.47 21.9 16.58 15.37 3.76 3.91 1.57 20.57 14.76 18.61] 94.58
9 [ 8.57 22.77 17.06 16.25 4.14 4. 1.56 22.97 14.09 19.09] 100.79
Restricted license - for non-production use only - expires 2023-10-25
Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 16 physical cores, 32 logical processors, using up to 32 threads
Optimize a model with 20 rows, 110 columns and 210 nonzeros
Model fingerprint: 0x1ff9913f
Variable types: 0 continuous, 110 integer (110 binary)
@ -790,7 +561,7 @@ H 0 0 4.0000000 1.27484 68.1% - 0s
H 0 0 2.0000000 1.27484 36.3% - 0s
0 0 1.27484 0 4 2.00000 1.27484 36.3% - 0s
Explored 1 nodes (38 simplex iterations) in 0.00 seconds (0.00 work units)
Explored 1 nodes (38 simplex iterations) in 0.01 seconds (0.00 work units)
Thread count was 32 (of 32 available processors)
Solution count 3: 2 4 5
@ -799,14 +570,23 @@ Optimal solution found (tolerance 1.00e-04)
Best objective 2.000000000000e+00, best bound 2.000000000000e+00, gap 0.0000%
</pre></div></div>
</div>
<div class="nboutput nblast docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area stderr docutils container">
<div class="highlight"><pre>
/home/axavier/.conda/envs/miplearn2/lib/python3.9/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
</pre></div></div>
</div>
</div>
</div>
<div class="section" id="Multi-Dimensional-Knapsack">
<h2><span class="section-number">1.3. </span>Multi-Dimensional Knapsack<a class="headerlink" href="#Multi-Dimensional-Knapsack" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">4.3. </span>Multi-Dimensional Knapsack<a class="headerlink" href="#Multi-Dimensional-Knapsack" title="Permalink to this headline"></a></h2>
<p>The <strong>multi-dimensional knapsack problem</strong> is a generalization of the classic knapsack problem, which involves selecting a subset of items to be placed in a knapsack such that the total value of the items is maximized without exceeding a maximum weight. In this generalization, items have multiple weights (representing multiple resources), and multiple weight constraints must be satisfied.</p>
<div class="section" id="id1">
<h3>Formulation<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3>
<p>Let <span class="math notranslate nohighlight">\(n\)</span> be the number of items and <span class="math notranslate nohighlight">\(m\)</span> be the number of resources. For each item <span class="math notranslate nohighlight">\(j\)</span> and resource <span class="math notranslate nohighlight">\(i\)</span>, let <span class="math notranslate nohighlight">\(p_j\)</span> be the price of the item, let <span class="math notranslate nohighlight">\(w_{ij}\)</span> be the amount of resource <span class="math notranslate nohighlight">\(j\)</span> item <span class="math notranslate nohighlight">\(i\)</span> consumes (i.e. the <span class="math notranslate nohighlight">\(j\)</span>-th weight of the item), and let <span class="math notranslate nohighlight">\(b_i\)</span> be the total amount of resource <span class="math notranslate nohighlight">\(i\)</span> available (or the size of the <span class="math notranslate nohighlight">\(j\)</span>-th knapsack). The formulation is given by:</p>
<p>Let <span class="math notranslate nohighlight">\(n\)</span> be the number of items and <span class="math notranslate nohighlight">\(m\)</span> be the number of resources. For each item <span class="math notranslate nohighlight">\(j\)</span> and resource <span class="math notranslate nohighlight">\(i\)</span>, let <span class="math notranslate nohighlight">\(p_j\)</span> be the price of the item, let <span class="math notranslate nohighlight">\(w_{ij}\)</span> be the amount of resource <span class="math notranslate nohighlight">\(j\)</span> item <span class="math notranslate nohighlight">\(i\)</span> consumes (i.e. the <span class="math notranslate nohighlight">\(j\)</span>-th weight of the item), and let <span class="math notranslate nohighlight">\(b_i\)</span> be the total amount of resource <span class="math notranslate nohighlight">\(i\)</span> available (or the size of the <span class="math notranslate nohighlight">\(j\)</span>-th knapsack). The formulation is given by:</p>
<div class="math notranslate nohighlight">
\[\begin{split}\begin{align*}
\text{minimize}\;\;\;
@ -878,7 +658,7 @@ Best objective 2.000000000000e+00, best bound 2.000000000000e+00, gap 0.0000%
<span class="c1"># Build model and optimize</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">build_multiknapsack_model</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">model</span><span class="o">.</span><span class="n">optimize</span><span class="p">()</span>
</pre></div>
<br/></pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
@ -897,8 +677,11 @@ weights
capacities
[1310. 988. 1004. 1269. 1007.]
Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 16 physical cores, 32 logical processors, using up to 32 threads
Optimize a model with 5 rows, 10 columns and 50 nonzeros
Model fingerprint: 0xaf3ac15e
Variable types: 0 continuous, 10 integer (10 binary)
@ -924,7 +707,7 @@ H 0 0 -1279.000000 -1428.7265 11.7% - 0s
Cutting planes:
Cover: 1
Explored 1 nodes (4 simplex iterations) in 0.00 seconds (0.00 work units)
Explored 1 nodes (4 simplex iterations) in 0.01 seconds (0.00 work units)
Thread count was 32 (of 32 available processors)
Solution count 2: -1279 -804
@ -937,7 +720,7 @@ Best objective -1.279000000000e+03, best bound -1.279000000000e+03, gap 0.0000%
</div>
</div>
<div class="section" id="Capacitated-P-Median">
<h2><span class="section-number">1.4. </span>Capacitated P-Median<a class="headerlink" href="#Capacitated-P-Median" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">4.4. </span>Capacitated P-Median<a class="headerlink" href="#Capacitated-P-Median" title="Permalink to this headline"></a></h2>
<p>The <strong>capacitated p-median</strong> problem is a variation of the classic <span class="math notranslate nohighlight">\(p\)</span>-median problem, in which a set of customers must be served by a set of facilities. In the capacitated <span class="math notranslate nohighlight">\(p\)</span>-Median problem, each facility has a fixed capacity, and the goal is to minimize the total cost of serving the customers while ensuring that the capacity of each facility is not exceeded. Variations of problem are often used in logistics and supply chain management to determine the most efficient locations for
warehouses or distribution centers.</p>
<div class="section" id="id4">
@ -1002,7 +785,7 @@ list of instances that have the same set of customers, but slightly different de
<span class="c1"># Build and optimize model</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">build_pmedian_model</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">model</span><span class="o">.</span><span class="n">optimize</span><span class="p">()</span>
</pre></div>
<br/></pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
@ -1025,8 +808,11 @@ distances =
demands = [6.12 1.39 2.92 3.66 4.56 7.85 2. 5.14 5.92 0.46]
capacities = [151.89 42.63 16.26 237.22 241.41 202.1 76.15 24.42 171.06 110.04]
Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 16 physical cores, 32 logical processors, using up to 32 threads
Optimize a model with 21 rows, 110 columns and 220 nonzeros
Model fingerprint: 0x8d8d9346
Variable types: 0 continuous, 110 integer (110 binary)
@ -1059,7 +845,7 @@ H 0 0 93.9200000 64.28872 31.5% - 0s
0 0 86.06884 0 15 93.92000 86.06884 8.36% - 0s
* 0 0 0 91.2300000 91.23000 0.00% - 0s
Explored 1 nodes (60 simplex iterations) in 0.01 seconds (0.00 work units)
Explored 1 nodes (70 simplex iterations) in 0.02 seconds (0.00 work units)
Thread count was 32 (of 32 available processors)
Solution count 10: 91.23 93.92 93.98 ... 368.79
@ -1071,7 +857,7 @@ Best objective 9.123000000000e+01, best bound 9.123000000000e+01, gap 0.0000%
</div>
</div>
<div class="section" id="Set-cover">
<h2><span class="section-number">1.5. </span>Set cover<a class="headerlink" href="#Set-cover" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">4.5. </span>Set cover<a class="headerlink" href="#Set-cover" title="Permalink to this headline"></a></h2>
<p>The <strong>set cover problem</strong> is a classical NP-hard optimization problem which aims to minimize the number of sets needed to cover all elements in a given universe. Each set may contain a different number of elements, and sets may overlap with each other. This problem can be useful in various real-world scenarios such as scheduling, resource allocation, and network design.</p>
<div class="section" id="id7">
<h3>Formulation<a class="headerlink" href="#id7" title="Permalink to this headline"></a></h3>
@ -1106,7 +892,7 @@ Best objective 9.123000000000e+01, best bound 9.123000000000e+01, gap 0.0000%
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">from</span> <span class="nn">scipy.stats</span> <span class="kn">import</span> <span class="n">uniform</span><span class="p">,</span> <span class="n">randint</span>
<span class="kn">from</span> <span class="nn">miplearn.problems.setcover</span> <span class="kn">import</span> <span class="n">SetCoverGenerator</span><span class="p">,</span> <span class="n">build_setcover_model</span>
<span class="kn">from</span> <span class="nn">miplearn.problems.setcover</span> <span class="kn">import</span> <span class="n">SetCoverGenerator</span><span class="p">,</span> <span class="n">build_setcover_model_gurobipy</span>
<span class="c1"># Set random seed, to make example reproducible</span>
<span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
@ -1130,9 +916,9 @@ Best objective 9.123000000000e+01, best bound 9.123000000000e+01, gap 0.0000%
<span class="nb">print</span><span class="p">()</span>
<span class="c1"># Build and optimize model</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">build_setcover_model</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">build_setcover_model_gurobipy</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">model</span><span class="o">.</span><span class="n">optimize</span><span class="p">()</span>
</pre></div>
<br/></pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
@ -1149,8 +935,11 @@ matrix
costs [1044.58 850.13 1014.5 944.83 697.9 971.87 213.49 220.98 70.23
425.33]
Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 16 physical cores, 32 logical processors, using up to 32 threads
Optimize a model with 5 rows, 10 columns and 28 nonzeros
Model fingerprint: 0xe5c2d4fa
Variable types: 0 continuous, 10 integer (10 binary)
@ -1176,7 +965,7 @@ Best objective 2.134900000000e+02, best bound 2.134900000000e+02, gap 0.0000%
</div>
</div>
<div class="section" id="Set-Packing">
<h2><span class="section-number">1.6. </span>Set Packing<a class="headerlink" href="#Set-Packing" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">4.6. </span>Set Packing<a class="headerlink" href="#Set-Packing" title="Permalink to this headline"></a></h2>
<p><strong>Set packing</strong> is a classical optimization problem that asks for the maximum number of disjoint sets within a given list. This problem often arises in real-world situations where a finite number of resources need to be allocated to tasks, such as airline flight crew scheduling.</p>
<div class="section" id="id10">
<h3>Formulation<a class="headerlink" href="#id10" title="Permalink to this headline"></a></h3>
@ -1229,7 +1018,7 @@ Best objective 2.134900000000e+02, best bound 2.134900000000e+02, gap 0.0000%
<span class="c1"># Build and optimize model</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">build_setpack_model</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">model</span><span class="o">.</span><span class="n">optimize</span><span class="p">()</span>
</pre></div>
<br/></pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
@ -1246,8 +1035,11 @@ matrix
costs [1044.58 850.13 1014.5 944.83 697.9 971.87 213.49 220.98 70.23
425.33]
Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 16 physical cores, 32 logical processors, using up to 32 threads
Optimize a model with 5 rows, 10 columns and 28 nonzeros
Model fingerprint: 0x4ee91388
Variable types: 0 continuous, 10 integer (10 binary)
@ -1274,7 +1066,7 @@ Best objective -1.986370000000e+03, best bound -1.986370000000e+03, gap 0.0000%
</div>
</div>
<div class="section" id="Stable-Set">
<h2><span class="section-number">1.7. </span>Stable Set<a class="headerlink" href="#Stable-Set" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">4.7. </span>Stable Set<a class="headerlink" href="#Stable-Set" title="Permalink to this headline"></a></h2>
<p>The <strong>maximum-weight stable set problem</strong> is a classical optimization problem in graph theory which asks for the maximum-weight subset of vertices in a graph such that no two vertices in the subset are adjacent. The problem often arises in real-world scheduling or resource allocation situations, where stable sets represent tasks or resources that can be chosen simultaneously without conflicts.</p>
<div class="section" id="id13">
<h3>Formulation<a class="headerlink" href="#id13" title="Permalink to this headline"></a></h3>
@ -1296,13 +1088,16 @@ other. The class then samples the provided probability distribution <code class=
<div class="section" id="id15">
<h3>Example<a class="headerlink" href="#id15" title="Permalink to this headline"></a></h3>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[24]:
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[6]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">random</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">from</span> <span class="nn">scipy.stats</span> <span class="kn">import</span> <span class="n">uniform</span><span class="p">,</span> <span class="n">randint</span>
<span class="kn">from</span> <span class="nn">miplearn.problems.stab</span> <span class="kn">import</span> <span class="n">MaxWeightStableSetGenerator</span><span class="p">,</span> <span class="n">build_stab_model</span>
<span class="kn">from</span> <span class="nn">miplearn.problems.stab</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">MaxWeightStableSetGenerator</span><span class="p">,</span>
<span class="n">build_stab_model_gurobipy</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Set random seed to make example reproducible</span>
<span class="n">random</span><span class="o">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
@ -1324,9 +1119,9 @@ other. The class then samples the provided probability distribution <code class=
<span class="nb">print</span><span class="p">()</span>
<span class="c1"># Load and optimize the first instance</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">build_stab_model</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">build_stab_model_gurobipy</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">model</span><span class="o">.</span><span class="n">optimize</span><span class="p">()</span>
</pre></div>
<br/></pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
@ -1338,8 +1133,11 @@ graph [(0, 2), (0, 4), (0, 8), (1, 2), (1, 3), (1, 5), (1, 6), (1, 9), (2, 5), (
weights[0] [37.45 95.07 73.2 59.87 15.6 15.6 5.81 86.62 60.11 70.81]
weights[1] [ 2.06 96.99 83.24 21.23 18.18 18.34 30.42 52.48 43.19 29.12]
Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 16 physical cores, 32 logical processors, using up to 32 threads
Optimize a model with 10 rows, 10 columns and 24 nonzeros
Model fingerprint: 0xf4c21689
Variable types: 0 continuous, 10 integer (10 binary)
@ -1361,7 +1159,7 @@ Root relaxation: objective -2.205650e+02, 4 iterations, 0.00 seconds (0.00 work
0 0 infeasible 0 -219.14000 -219.14000 0.00% - 0s
Explored 1 nodes (4 simplex iterations) in 0.00 seconds (0.00 work units)
Explored 1 nodes (4 simplex iterations) in 0.01 seconds (0.00 work units)
Thread count was 32 (of 32 available processors)
Solution count 1: -219.14
@ -1374,7 +1172,7 @@ Best objective -2.191400000000e+02, best bound -2.191400000000e+02, gap 0.0000%
</div>
</div>
<div class="section" id="Traveling-Salesman">
<h2><span class="section-number">1.8. </span>Traveling Salesman<a class="headerlink" href="#Traveling-Salesman" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">4.8. </span>Traveling Salesman<a class="headerlink" href="#Traveling-Salesman" title="Permalink to this headline"></a></h2>
<p>Given a list of cities and the distances between them, the <strong>traveling salesman problem</strong> asks for the shortest route starting at the first city, visiting each other city exactly once, then returning to the first city. This problem is a generalization of the Hamiltonian path problem, one of Karps 21 NP-complete problems, and has many practical applications, including routing delivery trucks and scheduling airline routes.</p>
<div class="section" id="id16">
<h3>Formulation<a class="headerlink" href="#id16" title="Permalink to this headline"></a></h3>
@ -1402,7 +1200,7 @@ Best objective -2.191400000000e+02, best bound -2.191400000000e+02, gap 0.0000%
<div class="section" id="id18">
<h3>Example<a class="headerlink" href="#id18" title="Permalink to this headline"></a></h3>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[32]:
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[7]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">random</span>
@ -1433,7 +1231,7 @@ Best objective -2.191400000000e+02, best bound -2.191400000000e+02, gap 0.0000%
<span class="c1"># Load and optimize the first instance</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">build_tsp_model</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">model</span><span class="o">.</span><span class="n">optimize</span><span class="p">()</span>
</pre></div>
<br/></pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
@ -1465,8 +1263,11 @@ distances[1]
[ 668. 446. 317. 648. 469. 752. 394. 286. 274. 0.]]
Set parameter LazyConstraints to value 1
Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 16 physical cores, 32 logical processors, using up to 32 threads
Optimize a model with 10 rows, 45 columns and 90 nonzeros
Model fingerprint: 0x719675e5
Variable types: 0 continuous, 45 integer (45 binary)
@ -1497,13 +1298,13 @@ Solution count 1: 2921
Optimal solution found (tolerance 1.00e-04)
Best objective 2.921000000000e+03, best bound 2.921000000000e+03, gap 0.0000%
User-callback calls 100, time in user-callback 0.00 sec
User-callback calls 106, time in user-callback 0.00 sec
</pre></div></div>
</div>
</div>
</div>
<div class="section" id="Unit-Commitment">
<h2><span class="section-number">1.9. </span>Unit Commitment<a class="headerlink" href="#Unit-Commitment" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">4.9. </span>Unit Commitment<a class="headerlink" href="#Unit-Commitment" title="Permalink to this headline"></a></h2>
<p>The <strong>unit commitment problem</strong> is a mixed-integer optimization problem which asks which power generation units should be turned on and off, at what time, and at what capacity, in order to meet the demand for electricity generation at the lowest cost. Numerous operational constraints are typically enforced, such as <em>ramping constraints</em>, which prevent generation units from changing power output levels too quickly from one time step to the next, and <em>minimum-up</em> and <em>minimum-down</em> constraints,
which prevent units from switching on and off too frequently. The unit commitment problem is widely used in power systems planning and operations.</p>
<div class="admonition note">
@ -1605,7 +1406,7 @@ enforce bounds to the quantity of power generated by each unit.</p>
<span class="c1"># Load and optimize the first instance</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">build_uc_model</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">model</span><span class="o">.</span><span class="n">optimize</span><span class="p">()</span>
</pre></div>
<br/></pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
@ -1639,8 +1440,11 @@ demand[1]
828.28 775.18 834.99 959.76 865.72 1193.52 1058.92 985.19 893.92
962.16 781.88 723.15 639.04 602.4 787.02]
Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)
Thread count: 6 physical cores, 12 logical processors, using up to 12 threads
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 16 physical cores, 32 logical processors, using up to 32 threads
Optimize a model with 578 rows, 360 columns and 2128 nonzeros
Model fingerprint: 0x4dc1c661
Variable types: 120 continuous, 240 integer (240 binary)
@ -1650,22 +1454,22 @@ Coefficient statistics:
Bounds range [1e+00, 1e+00]
RHS range [1e+00, 1e+03]
Presolve removed 244 rows and 131 columns
Presolve time: 0.01s
Presolve time: 0.02s
Presolved: 334 rows, 229 columns, 842 nonzeros
Variable types: 116 continuous, 113 integer (113 binary)
Found heuristic solution: objective 441426.66550
Found heuristic solution: objective 440662.46430
Found heuristic solution: objective 429461.97680
Found heuristic solution: objective 374043.64040
Root relaxation: objective 3.361348e+05, 139 iterations, 0.00 seconds (0.00 work units)
Root relaxation: objective 3.361348e+05, 142 iterations, 0.00 seconds (0.00 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
0 0 336134.820 0 18 374043.640 336134.820 10.1% - 0s
H 0 0 368600.14450 336134.820 8.81% - 0s
H 0 0 364721.76610 364721.766 0.00% - 0s
0 0 - 0 364721.766 364721.766 0.00% - 0s
H 0 0 364721.76610 336134.820 7.84% - 0s
0 0 cutoff 0 364721.766 364721.766 0.00% - 0s
Cutting planes:
Gomory: 3
@ -1677,10 +1481,10 @@ Cutting planes:
RLT: 1
Relax-and-lift: 7
Explored 1 nodes (232 simplex iterations) in 0.04 seconds (0.02 work units)
Thread count was 12 (of 12 available processors)
Explored 1 nodes (234 simplex iterations) in 0.04 seconds (0.02 work units)
Thread count was 32 (of 32 available processors)
Solution count 5: 364722 368600 374044 ... 441427
Solution count 5: 364722 368600 374044 ... 440662
Optimal solution found (tolerance 1.00e-04)
Best objective 3.647217661000e+05, best bound 3.647217661000e+05, gap 0.0000%
@ -1689,7 +1493,7 @@ Best objective 3.647217661000e+05, best bound 3.647217661000e+05, gap 0.0000%
</div>
</div>
<div class="section" id="Vertex-Cover">
<h2><span class="section-number">1.10. </span>Vertex Cover<a class="headerlink" href="#Vertex-Cover" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">4.10. </span>Vertex Cover<a class="headerlink" href="#Vertex-Cover" title="Permalink to this headline"></a></h2>
<p><strong>Minimum weight vertex cover</strong> is a classical optimization problem in graph theory where the goal is to find the minimum-weight set of vertices that are connected to all of the edges in the graph. The problem generalizes one of Karps 21 NP-complete problems and has applications in various fields, including bioinformatics and machine learning.</p>
<div class="section" id="id22">
<h3>Formulation<a class="headerlink" href="#id22" title="Permalink to this headline"></a></h3>
@ -1706,7 +1510,7 @@ Best objective 3.647217661000e+05, best bound 3.647217661000e+05, gap 0.0000%
</div>
<div class="section" id="id23">
<h3>Random instance generator<a class="headerlink" href="#id23" title="Permalink to this headline"></a></h3>
<p>The class <a class="reference external" href="../../api/problems/#module-miplearn.problems.vertexcover">MinWeightVertexCoverGenerator</a> can be used to generate random instances of this problem. The class accepts exactly the same parameters and behaves exactly in the same way as <a class="reference external" href="../../api/problems/#miplearn.problems.stab.MaxWeightStableSetGenerator">MaxWeightStableSetGenerator</a>. See the <a class="reference external" href="#Stable-Set">stable set section</a> for more details.</p>
<p>The class <a class="reference external" href="../../api/problems/#module-miplearn.problems.vertexcover">MinWeightVertexCoverGenerator</a> can be used to generate random instances of this problem. The class accepts exactly the same parameters and behaves exactly in the same way as <a class="reference external" href="../../api/problems/#miplearn.problems.stab.MaxWeightStableSetGenerator">MaxWeightStableSetGenerator</a>. See the <a class="reference internal" href="#Stable-Set"><span class="std std-ref">stable set section</span></a> for more details.</p>
</div>
<div class="section" id="id24">
<h3>Example<a class="headerlink" href="#id24" title="Permalink to this headline"></a></h3>
@ -1717,7 +1521,10 @@ Best objective 3.647217661000e+05, best bound 3.647217661000e+05, gap 0.0000%
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">random</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">from</span> <span class="nn">scipy.stats</span> <span class="kn">import</span> <span class="n">uniform</span><span class="p">,</span> <span class="n">randint</span>
<span class="kn">from</span> <span class="nn">miplearn.problems.vertexcover</span> <span class="kn">import</span> <span class="n">MinWeightVertexCoverGenerator</span><span class="p">,</span> <span class="n">build_vertexcover_model</span>
<span class="kn">from</span> <span class="nn">miplearn.problems.vertexcover</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">MinWeightVertexCoverGenerator</span><span class="p">,</span>
<span class="n">build_vertexcover_model</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Set random seed to make example reproducible</span>
<span class="n">random</span><span class="o">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
@ -1753,8 +1560,11 @@ graph [(0, 2), (0, 4), (0, 8), (1, 2), (1, 3), (1, 5), (1, 6), (1, 9), (2, 5), (
weights[0] [37.45 95.07 73.2 59.87 15.6 15.6 5.81 86.62 60.11 70.81]
weights[1] [ 2.06 96.99 83.24 21.23 18.18 18.34 30.42 52.48 43.19 29.12]
Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)
Thread count: 6 physical cores, 12 logical processors, using up to 12 threads
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 16 physical cores, 32 logical processors, using up to 32 threads
Optimize a model with 15 rows, 10 columns and 30 nonzeros
Model fingerprint: 0x2d2d1390
Variable types: 0 continuous, 10 integer (10 binary)
@ -1777,7 +1587,7 @@ Root relaxation: objective 2.995750e+02, 8 iterations, 0.00 seconds (0.00 work u
0 0 infeasible 0 301.00000 301.00000 0.00% - 0s
Explored 1 nodes (8 simplex iterations) in 0.01 seconds (0.00 work units)
Thread count was 12 (of 12 available processors)
Thread count was 32 (of 32 available processors)
Solution count 1: 301
@ -1803,8 +1613,8 @@ Best objective 3.010000000000e+02, best bound 3.010000000000e+02, gap 0.0000%
<div class='prev-next-bottom'>
<a class='left-prev' id="prev-link" href="../../" title="previous page">MIPLearn</a>
<a class='right-next' id="next-link" href="../collectors/" title="next page"><span class="section-number">2. </span>Training Data Collectors</a>
<a class='left-prev' id="prev-link" href="../../tutorials/getting-started-jump/" title="previous page"><span class="section-number">3. </span>Getting started (JuMP)</a>
<a class='right-next' id="next-link" href="../collectors/" title="next page"><span class="section-number">5. </span>Training Data Collectors</a>
</div>
@ -1814,7 +1624,7 @@ Best objective 3.010000000000e+02, best bound 3.010000000000e+02, gap 0.0000%
<div class="container">
<p>
&copy; Copyright 2020-2022, UChicago Argonne, LLC.<br/>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>

@ -14,16 +14,28 @@
},
{
"cell_type": "code",
"execution_count": 3,
"id": "dac704b5",
"execution_count": 1,
"id": "92b09b98",
"metadata": {
"collapsed": false
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/axavier/Software/anaconda3/envs/miplearn/lib/python3.8/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Restricted license - for non-production use only - expires 2023-10-25\n",
"Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"Optimize a model with 10 rows, 45 columns and 90 nonzeros\n",
@ -71,7 +83,7 @@
"Cutting planes:\n",
" Lazy constraints: 3\n",
"\n",
"Explored 1 nodes (15 simplex iterations) in 0.02 seconds (0.00 work units)\n",
"Explored 1 nodes (15 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 1: 2796 \n",
@ -152,7 +164,7 @@
"test_data = all_data[40:]\n",
"\n",
"# Collect training data\n",
"bc = BasicCollector(time_limit_sec=3600)\n",
"bc = BasicCollector()\n",
"bc.collect(train_data, build_tsp_model, n_jobs=4)\n",
"\n",
"# Build learning solver\n",
@ -180,7 +192,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 1,
"id": "e27d2cbd-5341-461d-bbc1-8131aee8d949",
"metadata": {},
"outputs": [],
@ -189,7 +201,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},

@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>5. Solvers &#8212; MIPLearn 0.3</title>
<title>8. Solvers &#8212; MIPLearn 0.3</title>
<link href="../../_static/css/theme.css" rel="stylesheet" />
<link href="../../_static/css/index.c5995385ac14fb8791e8eb36b4908be2.css" rel="stylesheet" />
@ -24,6 +24,11 @@
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../_static/sphinx-book-theme.acff12b8f9c144ce68a297486a2fa670.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/custom.css" />
<link rel="preload" as="script" href="../../_static/js/index.1c5a1a01449ed65a7b51.js">
@ -38,8 +43,8 @@
<script type="text/x-mathjax-config">MathJax.Hub.Config({"tex2jax": {"inlineMath": [["\\(", "\\)"]], "displayMath": [["\\[", "\\]"]], "processRefs": false, "processEnvironments": false}})</script>
<link rel="index" title="Index" href="../../genindex/" />
<link rel="search" title="Search" href="../../search/" />
<link rel="next" title="6. Benchmark Problems" href="../../api/problems/" />
<link rel="prev" title="4. Primal Components" href="../primal/" />
<link rel="next" title="9. Benchmark Problems" href="../../api/problems/" />
<link rel="prev" title="7. Primal Components" href="../primal/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="docsearch:language" content="en" />
@ -68,6 +73,28 @@
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../tutorials/getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
@ -75,59 +102,59 @@
<ul class="current nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../problems/">
1. Benchmark Problems
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../collectors/">
2. Training Data Collectors
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../features/">
3. Feature Extractors
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../primal/">
4. Primal Components
7. Primal Components
</a>
</li>
<li class="toctree-l1 current active">
<a class="current reference internal" href="#">
5. Solvers
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
API Reference
Python API Reference
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../api/problems/">
6. Benchmark Problems
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/collectors/">
7. Collectors &amp; Extractors
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/components/">
8. Components
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/solvers/">
9. Solvers
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/helpers/">
10. Helpers
13. Helpers
</a>
</li>
</ul>
@ -199,7 +226,7 @@
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#LearningSolver">
5.1. LearningSolver
8.1. LearningSolver
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
@ -220,271 +247,14 @@
<div>
<style>
/* CSS for nbsphinx extension */
/* remove conflicting styling from Sphinx themes */
div.nbinput.container div.prompt *,
div.nboutput.container div.prompt *,
div.nbinput.container div.input_area pre,
div.nboutput.container div.output_area pre,
div.nbinput.container div.input_area .highlight,
div.nboutput.container div.output_area .highlight {
border: none;
padding: 0;
margin: 0;
box-shadow: none;
}
div.nbinput.container > div[class*=highlight],
div.nboutput.container > div[class*=highlight] {
margin: 0;
}
div.nbinput.container div.prompt *,
div.nboutput.container div.prompt * {
background: none;
}
div.nboutput.container div.output_area .highlight,
div.nboutput.container div.output_area pre {
background: unset;
}
div.nboutput.container div.output_area div.highlight {
color: unset; /* override Pygments text color */
}
/* avoid gaps between output lines */
div.nboutput.container div[class*=highlight] pre {
line-height: normal;
}
/* input/output containers */
div.nbinput.container,
div.nboutput.container {
display: -webkit-flex;
display: flex;
align-items: flex-start;
margin: 0;
width: 100%;
}
@media (max-width: 540px) {
div.nbinput.container,
div.nboutput.container {
flex-direction: column;
}
}
/* input container */
div.nbinput.container {
padding-top: 5px;
}
/* last container */
div.nblast.container {
padding-bottom: 5px;
}
/* input prompt */
div.nbinput.container div.prompt pre {
color: #307FC1;
}
/* output prompt */
div.nboutput.container div.prompt pre {
color: #BF5B3D;
}
/* all prompts */
div.nbinput.container div.prompt,
div.nboutput.container div.prompt {
width: 4.5ex;
padding-top: 5px;
position: relative;
user-select: none;
}
div.nbinput.container div.prompt > div,
div.nboutput.container div.prompt > div {
position: absolute;
right: 0;
margin-right: 0.3ex;
}
@media (max-width: 540px) {
div.nbinput.container div.prompt,
div.nboutput.container div.prompt {
width: unset;
text-align: left;
padding: 0.4em;
}
div.nboutput.container div.prompt.empty {
padding: 0;
}
div.nbinput.container div.prompt > div,
div.nboutput.container div.prompt > div {
position: unset;
}
}
/* disable scrollbars and line breaks on prompts */
div.nbinput.container div.prompt pre,
div.nboutput.container div.prompt pre {
overflow: hidden;
white-space: pre;
}
/* input/output area */
div.nbinput.container div.input_area,
div.nboutput.container div.output_area {
-webkit-flex: 1;
flex: 1;
overflow: auto;
}
@media (max-width: 540px) {
div.nbinput.container div.input_area,
div.nboutput.container div.output_area {
width: 100%;
}
}
/* input area */
div.nbinput.container div.input_area {
border: 1px solid #e0e0e0;
border-radius: 2px;
/*background: #f5f5f5;*/
}
/* override MathJax center alignment in output cells */
div.nboutput.container div[class*=MathJax] {
text-align: left !important;
}
/* override sphinx.ext.imgmath center alignment in output cells */
div.nboutput.container div.math p {
text-align: left;
}
/* standard error */
div.nboutput.container div.output_area.stderr {
background: #fdd;
}
/* ANSI colors */
.ansi-black-fg { color: #3E424D; }
.ansi-black-bg { background-color: #3E424D; }
.ansi-black-intense-fg { color: #282C36; }
.ansi-black-intense-bg { background-color: #282C36; }
.ansi-red-fg { color: #E75C58; }
.ansi-red-bg { background-color: #E75C58; }
.ansi-red-intense-fg { color: #B22B31; }
.ansi-red-intense-bg { background-color: #B22B31; }
.ansi-green-fg { color: #00A250; }
.ansi-green-bg { background-color: #00A250; }
.ansi-green-intense-fg { color: #007427; }
.ansi-green-intense-bg { background-color: #007427; }
.ansi-yellow-fg { color: #DDB62B; }
.ansi-yellow-bg { background-color: #DDB62B; }
.ansi-yellow-intense-fg { color: #B27D12; }
.ansi-yellow-intense-bg { background-color: #B27D12; }
.ansi-blue-fg { color: #208FFB; }
.ansi-blue-bg { background-color: #208FFB; }
.ansi-blue-intense-fg { color: #0065CA; }
.ansi-blue-intense-bg { background-color: #0065CA; }
.ansi-magenta-fg { color: #D160C4; }
.ansi-magenta-bg { background-color: #D160C4; }
.ansi-magenta-intense-fg { color: #A03196; }
.ansi-magenta-intense-bg { background-color: #A03196; }
.ansi-cyan-fg { color: #60C6C8; }
.ansi-cyan-bg { background-color: #60C6C8; }
.ansi-cyan-intense-fg { color: #258F8F; }
.ansi-cyan-intense-bg { background-color: #258F8F; }
.ansi-white-fg { color: #C5C1B4; }
.ansi-white-bg { background-color: #C5C1B4; }
.ansi-white-intense-fg { color: #A1A6B2; }
.ansi-white-intense-bg { background-color: #A1A6B2; }
.ansi-default-inverse-fg { color: #FFFFFF; }
.ansi-default-inverse-bg { background-color: #000000; }
.ansi-bold { font-weight: bold; }
.ansi-underline { text-decoration: underline; }
div.nbinput.container div.input_area div[class*=highlight] > pre,
div.nboutput.container div.output_area div[class*=highlight] > pre,
div.nboutput.container div.output_area div[class*=highlight].math,
div.nboutput.container div.output_area.rendered_html,
div.nboutput.container div.output_area > div.output_javascript,
div.nboutput.container div.output_area:not(.rendered_html) > img{
padding: 5px;
margin: 0;
}
/* fix copybtn overflow problem in chromium (needed for 'sphinx_copybutton') */
div.nbinput.container div.input_area > div[class^='highlight'],
div.nboutput.container div.output_area > div[class^='highlight']{
overflow-y: hidden;
}
/* hide copybtn icon on prompts (needed for 'sphinx_copybutton') */
.prompt .copybtn {
display: none;
}
/* Some additional styling taken form the Jupyter notebook CSS */
.jp-RenderedHTMLCommon table,
div.rendered_html table {
border: none;
border-collapse: collapse;
border-spacing: 0;
color: black;
font-size: 12px;
table-layout: fixed;
}
.jp-RenderedHTMLCommon thead,
div.rendered_html thead {
border-bottom: 1px solid black;
vertical-align: bottom;
}
.jp-RenderedHTMLCommon tr,
.jp-RenderedHTMLCommon th,
.jp-RenderedHTMLCommon td,
div.rendered_html tr,
div.rendered_html th,
div.rendered_html td {
text-align: right;
vertical-align: middle;
padding: 0.5em 0.5em;
line-height: normal;
white-space: normal;
max-width: none;
border: none;
}
.jp-RenderedHTMLCommon th,
div.rendered_html th {
font-weight: bold;
}
.jp-RenderedHTMLCommon tbody tr:nth-child(odd),
div.rendered_html tbody tr:nth-child(odd) {
background: #f5f5f5;
}
.jp-RenderedHTMLCommon tbody tr:hover,
div.rendered_html tbody tr:hover {
background: rgba(66, 165, 245, 0.2);
}
</style>
<div class="section" id="Solvers">
<h1><span class="section-number">5. </span>Solvers<a class="headerlink" href="#Solvers" title="Permalink to this headline"></a></h1>
<div class="section" id="Solvers">
<h1><span class="section-number">8. </span>Solvers<a class="headerlink" href="#Solvers" title="Permalink to this headline"></a></h1>
<div class="section" id="LearningSolver">
<h2><span class="section-number">5.1. </span>LearningSolver<a class="headerlink" href="#LearningSolver" title="Permalink to this headline"></a></h2>
<h2><span class="section-number">8.1. </span>LearningSolver<a class="headerlink" href="#LearningSolver" title="Permalink to this headline"></a></h2>
<div class="section" id="Example">
<h3>Example<a class="headerlink" href="#Example" title="Permalink to this headline"></a></h3>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[3]:
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[1]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">random</span>
@ -528,7 +298,7 @@ div.rendered_html tbody tr:hover {
<span class="n">test_data</span> <span class="o">=</span> <span class="n">all_data</span><span class="p">[</span><span class="mi">40</span><span class="p">:]</span>
<span class="c1"># Collect training data</span>
<span class="n">bc</span> <span class="o">=</span> <span class="n">BasicCollector</span><span class="p">(</span><span class="n">time_limit_sec</span><span class="o">=</span><span class="mi">3600</span><span class="p">)</span>
<span class="n">bc</span> <span class="o">=</span> <span class="n">BasicCollector</span><span class="p">()</span>
<span class="n">bc</span><span class="o">.</span><span class="n">collect</span><span class="p">(</span><span class="n">train_data</span><span class="p">,</span> <span class="n">build_tsp_model</span><span class="p">,</span> <span class="n">n_jobs</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
<span class="c1"># Build learning solver</span>
@ -555,11 +325,21 @@ div.rendered_html tbody tr:hover {
</pre></div>
</div>
</div>
<div class="nboutput docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area stderr docutils container">
<div class="highlight"><pre>
/home/axavier/Software/anaconda3/envs/miplearn/lib/python3.8/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
</pre></div></div>
</div>
<div class="nboutput nblast docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area docutils container">
<div class="highlight"><pre>
Restricted license - for non-production use only - expires 2023-10-25
Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)
Thread count: 6 physical cores, 12 logical processors, using up to 12 threads
Optimize a model with 10 rows, 45 columns and 90 nonzeros
@ -607,7 +387,7 @@ Root relaxation: objective 2.761000e+03, 14 iterations, 0.00 seconds (0.00 work
Cutting planes:
Lazy constraints: 3
Explored 1 nodes (15 simplex iterations) in 0.02 seconds (0.00 work units)
Explored 1 nodes (15 simplex iterations) in 0.01 seconds (0.00 work units)
Thread count was 12 (of 12 available processors)
Solution count 1: 2796
@ -646,7 +426,7 @@ User-callback calls 27, time in user-callback 0.00 sec
</pre></div></div>
</div>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[2]:
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[1]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span>
@ -663,8 +443,8 @@ User-callback calls 27, time in user-callback 0.00 sec
<div class='prev-next-bottom'>
<a class='left-prev' id="prev-link" href="../primal/" title="previous page"><span class="section-number">4. </span>Primal Components</a>
<a class='right-next' id="next-link" href="../../api/problems/" title="next page"><span class="section-number">6. </span>Benchmark Problems</a>
<a class='left-prev' id="prev-link" href="../primal/" title="previous page"><span class="section-number">7. </span>Primal Components</a>
<a class='right-next' id="next-link" href="../../api/problems/" title="next page"><span class="section-number">9. </span>Benchmark Problems</a>
</div>
@ -674,7 +454,7 @@ User-callback calls 27, time in user-callback 0.00 sec
<div class="container">
<p>
&copy; Copyright 2020-2022, UChicago Argonne, LLC.<br/>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>

@ -24,6 +24,11 @@
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/sphinx-book-theme.acff12b8f9c144ce68a297486a2fa670.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
<link rel="preload" as="script" href="_static/js/index.1c5a1a01449ed65a7b51.js">
@ -36,7 +41,7 @@
<script src="_static/sphinx-book-theme.12a9622fbb08dcb3a2a40b2c02b83a57.js"></script>
<link rel="index" title="Index" href="genindex/" />
<link rel="search" title="Search" href="search/" />
<link rel="next" title="1. Benchmark Problems" href="guide/problems/" />
<link rel="next" title="1. Getting started (Pyomo)" href="tutorials/getting-started-pyomo/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="docsearch:language" content="en" />
@ -65,6 +70,28 @@
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="tutorials/getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="tutorials/getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="tutorials/getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
@ -72,59 +99,59 @@
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="guide/problems/">
1. Benchmark Problems
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="guide/collectors/">
2. Training Data Collectors
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="guide/features/">
3. Feature Extractors
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="guide/primal/">
4. Primal Components
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="guide/solvers/">
5. Solvers
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
API Reference
Python API Reference
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="api/problems/">
6. Benchmark Problems
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="api/collectors/">
7. Collectors &amp; Extractors
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="api/components/">
8. Components
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="api/solvers/">
9. Solvers
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="api/helpers/">
10. Helpers
13. Helpers
</a>
</li>
</ul>
@ -219,59 +246,91 @@
<div class="section" id="contents">
<h2>Contents<a class="headerlink" href="#contents" title="Permalink to this headline"></a></h2>
<div class="toctree-wrapper compound">
<p class="caption"><span class="caption-text">Tutorials</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="tutorials/getting-started-pyomo/">1. Getting started (Pyomo)</a><ul>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-pyomo/#Introduction">1.1. Introduction</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-pyomo/#Installation">1.2. Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-pyomo/#Modeling-a-simple-optimization-problem">1.3. Modeling a simple optimization problem</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-pyomo/#Generating-training-data">1.4. Generating training data</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-pyomo/#Training-and-solving-test-instances">1.5. Training and solving test instances</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-pyomo/#Accessing-the-solution">1.6. Accessing the solution</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="tutorials/getting-started-gurobipy/">2. Getting started (Gurobipy)</a><ul>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-gurobipy/#Introduction">2.1. Introduction</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-gurobipy/#Installation">2.2. Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-gurobipy/#Modeling-a-simple-optimization-problem">2.3. Modeling a simple optimization problem</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-gurobipy/#Generating-training-data">2.4. Generating training data</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-gurobipy/#Training-and-solving-test-instances">2.5. Training and solving test instances</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-gurobipy/#Accessing-the-solution">2.6. Accessing the solution</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="tutorials/getting-started-jump/">3. Getting started (JuMP)</a><ul>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-jump/#Introduction">3.1. Introduction</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-jump/#Installation">3.2. Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-jump/#Modeling-a-simple-optimization-problem">3.3. Modeling a simple optimization problem</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-jump/#Generating-training-data">3.4. Generating training data</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-jump/#Training-and-solving-test-instances">3.5. Training and solving test instances</a></li>
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting-started-jump/#Accessing-the-solution">3.6. Accessing the solution</a></li>
</ul>
</li>
</ul>
</div>
<div class="toctree-wrapper compound">
<p class="caption"><span class="caption-text">User Guide</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="guide/problems/">1. Benchmark Problems</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Overview">1.1. Overview</a></li>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Bin-Packing">1.2. Bin Packing</a><ul>
<li class="toctree-l1"><a class="reference internal" href="guide/problems/">4. Benchmark Problems</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Overview">4.1. Overview</a></li>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Bin-Packing">4.2. Bin Packing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#Formulation">Formulation</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#Random-instance-generator">Random instance generator</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#Example">Example</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Multi-Dimensional-Knapsack">1.3. Multi-Dimensional Knapsack</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Multi-Dimensional-Knapsack">4.3. Multi-Dimensional Knapsack</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id1">Formulation</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id2">Random instance generator</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id3">Example</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Capacitated-P-Median">1.4. Capacitated P-Median</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Capacitated-P-Median">4.4. Capacitated P-Median</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id4">Formulation</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id5">Random instance generator</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id6">Example</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Set-cover">1.5. Set cover</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Set-cover">4.5. Set cover</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id7">Formulation</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id8">Random instance generator</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id9">Example</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Set-Packing">1.6. Set Packing</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Set-Packing">4.6. Set Packing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id10">Formulation</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id11">Random instance generator</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id12">Example</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Stable-Set">1.7. Stable Set</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Stable-Set">4.7. Stable Set</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id13">Formulation</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id14">Random instance generator</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id15">Example</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Traveling-Salesman">1.8. Traveling Salesman</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Traveling-Salesman">4.8. Traveling Salesman</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id16">Formulation</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id17">Random instance generator</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id18">Example</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Unit-Commitment">1.9. Unit Commitment</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Unit-Commitment">4.9. Unit Commitment</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id19">Formulation</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id20">Random instance generator</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id21">Example</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Vertex-Cover">1.10. Vertex Cover</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/problems/#Vertex-Cover">4.10. Vertex Cover</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id22">Formulation</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id23">Random instance generator</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/problems/#id24">Example</a></li>
@ -279,53 +338,53 @@
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="guide/collectors/">2. Training Data Collectors</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/collectors/#Overview">2.1. Overview</a></li>
<li class="toctree-l2"><a class="reference internal" href="guide/collectors/#HDF5-Format">2.2. HDF5 Format</a><ul>
<li class="toctree-l1"><a class="reference internal" href="guide/collectors/">5. Training Data Collectors</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/collectors/#Overview">5.1. Overview</a></li>
<li class="toctree-l2"><a class="reference internal" href="guide/collectors/#HDF5-Format">5.2. HDF5 Format</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/collectors/#Example">Example</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="guide/collectors/#Basic-collector">2.3. Basic collector</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/collectors/#Basic-collector">5.3. Basic collector</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/collectors/#Data-fields">Data fields</a></li>
<li class="toctree-l3"><a class="reference internal" href="guide/collectors/#id1">Example</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="guide/features/">3. Feature Extractors</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/features/#Overview">3.1. Overview</a></li>
<li class="toctree-l2"><a class="reference internal" href="guide/features/#H5FieldsExtractor">3.2. H5FieldsExtractor</a><ul>
<li class="toctree-l1"><a class="reference internal" href="guide/features/">6. Feature Extractors</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/features/#Overview">6.1. Overview</a></li>
<li class="toctree-l2"><a class="reference internal" href="guide/features/#H5FieldsExtractor">6.2. H5FieldsExtractor</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/features/#Example">Example</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="guide/features/#AlvLouWeh2017Extractor">3.3. AlvLouWeh2017Extractor</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/features/#AlvLouWeh2017Extractor">6.3. AlvLouWeh2017Extractor</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/features/#id1">Example</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="guide/primal/">4. Primal Components</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/primal/#Primal-component-actions">4.1. Primal component actions</a></li>
<li class="toctree-l2"><a class="reference internal" href="guide/primal/#Memorizing-primal-component">4.2. Memorizing primal component</a><ul>
<li class="toctree-l1"><a class="reference internal" href="guide/primal/">7. Primal Components</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/primal/#Primal-component-actions">7.1. Primal component actions</a></li>
<li class="toctree-l2"><a class="reference internal" href="guide/primal/#Memorizing-primal-component">7.2. Memorizing primal component</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/primal/#Examples">Examples</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="guide/primal/#Independent-vars-primal-component">4.3. Independent vars primal component</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/primal/#Independent-vars-primal-component">7.3. Independent vars primal component</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/primal/#id1">Examples</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="guide/primal/#Joint-vars-primal-component">4.4. Joint vars primal component</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/primal/#Joint-vars-primal-component">7.4. Joint vars primal component</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/primal/#id2">Examples</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="guide/primal/#Expert-primal-component">4.5. Expert primal component</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/primal/#Expert-primal-component">7.5. Expert primal component</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/primal/#Example">Example</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="guide/solvers/">5. Solvers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/solvers/#LearningSolver">5.1. LearningSolver</a><ul>
<li class="toctree-l1"><a class="reference internal" href="guide/solvers/">8. Solvers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="guide/solvers/#LearningSolver">8.1. LearningSolver</a><ul>
<li class="toctree-l3"><a class="reference internal" href="guide/solvers/#Example">Example</a></li>
</ul>
</li>
@ -334,45 +393,45 @@
</ul>
</div>
<div class="toctree-wrapper compound">
<p class="caption"><span class="caption-text">API Reference</span></p>
<p class="caption"><span class="caption-text">Python API Reference</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="api/problems/">6. Benchmark Problems</a><ul>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.binpack">6.1. miplearn.problems.binpack</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.multiknapsack">6.2. miplearn.problems.multiknapsack</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.pmedian">6.3. miplearn.problems.pmedian</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.setcover">6.4. miplearn.problems.setcover</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.setpack">6.5. miplearn.problems.setpack</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.stab">6.6. miplearn.problems.stab</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.tsp">6.7. miplearn.problems.tsp</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.uc">6.8. miplearn.problems.uc</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.vertexcover">6.9. miplearn.problems.vertexcover</a></li>
<li class="toctree-l1"><a class="reference internal" href="api/problems/">9. Benchmark Problems</a><ul>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.binpack">9.1. miplearn.problems.binpack</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.multiknapsack">9.2. miplearn.problems.multiknapsack</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.pmedian">9.3. miplearn.problems.pmedian</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.setcover">9.4. miplearn.problems.setcover</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.setpack">9.5. miplearn.problems.setpack</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.stab">9.6. miplearn.problems.stab</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.tsp">9.7. miplearn.problems.tsp</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.uc">9.8. miplearn.problems.uc</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/problems/#module-miplearn.problems.vertexcover">9.9. miplearn.problems.vertexcover</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="api/collectors/">7. Collectors &amp; Extractors</a><ul>
<li class="toctree-l2"><a class="reference internal" href="api/collectors/#module-miplearn.classifiers.minprob">7.1. miplearn.classifiers.minprob</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/collectors/#module-miplearn.classifiers.singleclass">7.2. miplearn.classifiers.singleclass</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/collectors/#module-miplearn.collectors.basic">7.3. miplearn.collectors.basic</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/collectors/#miplearn-features-fields">7.4. miplearn.features.fields</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/collectors/#miplearn-features-alvlouweh2017">7.5. miplearn.features.AlvLouWeh2017</a></li>
<li class="toctree-l1"><a class="reference internal" href="api/collectors/">10. Collectors &amp; Extractors</a><ul>
<li class="toctree-l2"><a class="reference internal" href="api/collectors/#module-miplearn.classifiers.minprob">10.1. miplearn.classifiers.minprob</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/collectors/#module-miplearn.classifiers.singleclass">10.2. miplearn.classifiers.singleclass</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/collectors/#module-miplearn.collectors.basic">10.3. miplearn.collectors.basic</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/collectors/#module-miplearn.extractors.fields">10.4. miplearn.extractors.fields</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/collectors/#module-miplearn.extractors.AlvLouWeh2017">10.5. miplearn.extractors.AlvLouWeh2017</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="api/components/">8. Components</a><ul>
<li class="toctree-l2"><a class="reference internal" href="api/components/#module-miplearn.components.primal.actions">8.1. miplearn.components.primal.actions</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/components/#module-miplearn.components.primal.expert">8.2. miplearn.components.primal.expert</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/components/#module-miplearn.components.primal.indep">8.3. miplearn.components.primal.indep</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/components/#module-miplearn.components.primal.joint">8.4. miplearn.components.primal.joint</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/components/#module-miplearn.components.primal.mem">8.5. miplearn.components.primal.mem</a></li>
<li class="toctree-l1"><a class="reference internal" href="api/components/">11. Components</a><ul>
<li class="toctree-l2"><a class="reference internal" href="api/components/#module-miplearn.components.primal.actions">11.1. miplearn.components.primal.actions</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/components/#module-miplearn.components.primal.expert">11.2. miplearn.components.primal.expert</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/components/#module-miplearn.components.primal.indep">11.3. miplearn.components.primal.indep</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/components/#module-miplearn.components.primal.joint">11.4. miplearn.components.primal.joint</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/components/#module-miplearn.components.primal.mem">11.5. miplearn.components.primal.mem</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="api/solvers/">9. Solvers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="api/solvers/#module-miplearn.solvers.abstract">9.1. miplearn.solvers.abstract</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/solvers/#module-miplearn.solvers.gurobi">9.2. miplearn.solvers.gurobi</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/solvers/#module-miplearn.solvers.learning">9.3. miplearn.solvers.learning</a></li>
<li class="toctree-l1"><a class="reference internal" href="api/solvers/">12. Solvers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="api/solvers/#module-miplearn.solvers.abstract">12.1. miplearn.solvers.abstract</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/solvers/#module-miplearn.solvers.gurobi">12.2. miplearn.solvers.gurobi</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/solvers/#module-miplearn.solvers.learning">12.3. miplearn.solvers.learning</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="api/helpers/">10. Helpers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="api/helpers/#module-miplearn.io">10.1. miplearn.io</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/helpers/#module-miplearn.h5">10.2. miplearn.h5</a></li>
<li class="toctree-l1"><a class="reference internal" href="api/helpers/">13. Helpers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="api/helpers/#module-miplearn.io">13.1. miplearn.io</a></li>
<li class="toctree-l2"><a class="reference internal" href="api/helpers/#module-miplearn.h5">13.2. miplearn.h5</a></li>
</ul>
</li>
</ul>
@ -386,7 +445,7 @@
<div class='prev-next-bottom'>
<a class='right-next' id="next-link" href="guide/problems/" title="next page"><span class="section-number">1. </span>Benchmark Problems</a>
<a class='right-next' id="next-link" href="tutorials/getting-started-pyomo/" title="next page"><span class="section-number">1. </span>Getting started (Pyomo)</a>
</div>
@ -396,7 +455,7 @@
<div class="container">
<p>
&copy; Copyright 2020-2022, UChicago Argonne, LLC.<br/>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>

Binary file not shown.

@ -24,6 +24,14 @@
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../_static/sphinx-book-theme.acff12b8f9c144ce68a297486a2fa670.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/custom.css" />
<link rel="preload" as="script" href="../_static/js/index.1c5a1a01449ed65a7b51.js">
@ -67,6 +75,28 @@
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../tutorials/getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../tutorials/getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../tutorials/getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
@ -74,59 +104,59 @@
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../guide/problems/">
1. Benchmark Problems
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../guide/collectors/">
2. Training Data Collectors
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../guide/features/">
3. Feature Extractors
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../guide/primal/">
4. Primal Components
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../guide/solvers/">
5. Solvers
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
API Reference
Python API Reference
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../api/problems/">
6. Benchmark Problems
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../api/collectors/">
7. Collectors &amp; Extractors
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../api/components/">
8. Components
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../api/solvers/">
9. Solvers
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../api/helpers/">
10. Helpers
13. Helpers
</a>
</li>
</ul>
@ -239,6 +269,16 @@
<td>&#160;&#160;&#160;
<a href="../api/components/#module-miplearn.components.primal.mem"><code class="xref">miplearn.components.primal.mem</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="../api/collectors/#module-miplearn.extractors.AlvLouWeh2017"><code class="xref">miplearn.extractors.AlvLouWeh2017</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="../api/collectors/#module-miplearn.extractors.fields"><code class="xref">miplearn.extractors.fields</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
@ -326,7 +366,7 @@
<div class="container">
<p>
&copy; Copyright 2020-2022, UChicago Argonne, LLC.<br/>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>

@ -24,6 +24,14 @@
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../_static/sphinx-book-theme.acff12b8f9c144ce68a297486a2fa670.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../_static/custom.css" />
<link rel="preload" as="script" href="../_static/js/index.1c5a1a01449ed65a7b51.js">
@ -70,6 +78,28 @@
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../tutorials/getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../tutorials/getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../tutorials/getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
@ -77,59 +107,59 @@
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../guide/problems/">
1. Benchmark Problems
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../guide/collectors/">
2. Training Data Collectors
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../guide/features/">
3. Feature Extractors
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../guide/primal/">
4. Primal Components
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../guide/solvers/">
5. Solvers
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
API Reference
Python API Reference
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../api/problems/">
6. Benchmark Problems
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../api/collectors/">
7. Collectors &amp; Extractors
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../api/components/">
8. Components
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../api/solvers/">
9. Solvers
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../api/helpers/">
10. Helpers
13. Helpers
</a>
</li>
</ul>
@ -221,7 +251,7 @@
<div class="container">
<p>
&copy; Copyright 2020-2022, UChicago Argonne, LLC.<br/>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>

File diff suppressed because one or more lines are too long

@ -0,0 +1,849 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "6b8983b1",
"metadata": {
"tags": []
},
"source": [
"# Getting started (Gurobipy)\n",
"\n",
"## Introduction\n",
"\n",
"**MIPLearn** is an open source framework that uses machine learning (ML) to accelerate the performance of mixed-integer programming solvers (e.g. Gurobi, CPLEX, XPRESS). In this tutorial, we will:\n",
"\n",
"1. Install the Python/Gurobipy version of MIPLearn\n",
"2. Model a simple optimization problem using Gurobipy\n",
"3. Generate training data and train the ML models\n",
"4. Use the ML models together Gurobi to solve new instances\n",
"\n",
"<div class=\"alert alert-info\">\n",
"Note\n",
" \n",
"The Python/Gurobipy version of MIPLearn is only compatible with the Gurobi Optimizer. For broader solver compatibility, see the Python/Pyomo and Julia/JuMP versions of the package.\n",
"</div>\n",
"\n",
"<div class=\"alert alert-warning\">\n",
"Warning\n",
" \n",
"MIPLearn is still in early development stage. If run into any bugs or issues, please submit a bug report in our GitHub repository. Comments, suggestions and pull requests are also very welcome!\n",
" \n",
"</div>\n"
]
},
{
"cell_type": "markdown",
"id": "02f0a927",
"metadata": {},
"source": [
"## Installation\n",
"\n",
"MIPLearn is available in two versions:\n",
"\n",
"- Python version, compatible with the Pyomo and Gurobipy modeling languages,\n",
"- Julia version, compatible with the JuMP modeling language.\n",
"\n",
"In this tutorial, we will demonstrate how to use and install the Python/Gurobipy version of the package. The first step is to install Python 3.8+ in your computer. See the [official Python website for more instructions](https://www.python.org/downloads/). After Python is installed, we proceed to install MIPLearn using `pip`:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "cd8a69c1",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:18:02.381829278Z",
"start_time": "2023-06-06T20:18:02.381532300Z"
}
},
"outputs": [],
"source": [
"# !pip install MIPLearn==0.3.0"
]
},
{
"cell_type": "markdown",
"id": "e8274543",
"metadata": {},
"source": [
"In addition to MIPLearn itself, we will also install Gurobi 10.0, a state-of-the-art commercial MILP solver. This step also install a demo license for Gurobi, which should able to solve the small optimization problems in this tutorial. A license is required for solving larger-scale problems."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "dcc8756c",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:18:15.537811992Z",
"start_time": "2023-06-06T20:18:13.449177860Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: gurobipy<10.1,>=10 in /home/axavier/Software/anaconda3/envs/miplearn/lib/python3.8/site-packages (10.0.1)\n"
]
}
],
"source": [
"!pip install 'gurobipy>=10,<10.1'"
]
},
{
"cell_type": "markdown",
"id": "a14e4550",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
" \n",
"Note\n",
" \n",
"In the code above, we install specific version of all packages to ensure that this tutorial keeps running in the future, even when newer (and possibly incompatible) versions of the packages are released. This is usually a recommended practice for all Python projects.\n",
" \n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "16b86823",
"metadata": {},
"source": [
"## Modeling a simple optimization problem\n",
"\n",
"To illustrate how can MIPLearn be used, we will model and solve a small optimization problem related to power systems optimization. The problem we discuss below is a simplification of the **unit commitment problem,** a practical optimization problem solved daily by electric grid operators around the world. \n",
"\n",
"Suppose that a utility company needs to decide which electrical generators should be online at each hour of the day, as well as how much power should each generator produce. More specifically, assume that the company owns $n$ generators, denoted by $g_1, \\ldots, g_n$. Each generator can either be online or offline. An online generator $g_i$ can produce between $p^\\text{min}_i$ to $p^\\text{max}_i$ megawatts of power, and it costs the company $c^\\text{fix}_i + c^\\text{var}_i y_i$, where $y_i$ is the amount of power produced. An offline generator produces nothing and costs nothing. The total amount of power to be produced needs to be exactly equal to the total demand $d$ (in megawatts).\n",
"\n",
"This simple problem can be modeled as a *mixed-integer linear optimization* problem as follows. For each generator $g_i$, let $x_i \\in \\{0,1\\}$ be a decision variable indicating whether $g_i$ is online, and let $y_i \\geq 0$ be a decision variable indicating how much power does $g_i$ produce. The problem is then given by:"
]
},
{
"cell_type": "markdown",
"id": "f12c3702",
"metadata": {},
"source": [
"$$\n",
"\\begin{align}\n",
"\\text{minimize } \\quad & \\sum_{i=1}^n \\left( c^\\text{fix}_i x_i + c^\\text{var}_i y_i \\right) \\\\\n",
"\\text{subject to } \\quad & y_i \\leq p^\\text{max}_i x_i & i=1,\\ldots,n \\\\\n",
"& y_i \\geq p^\\text{min}_i x_i & i=1,\\ldots,n \\\\\n",
"& \\sum_{i=1}^n y_i = d \\\\\n",
"& x_i \\in \\{0,1\\} & i=1,\\ldots,n \\\\\n",
"& y_i \\geq 0 & i=1,\\ldots,n\n",
"\\end{align}\n",
"$$"
]
},
{
"cell_type": "markdown",
"id": "be3989ed",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
"\n",
"Note\n",
"\n",
"We use a simplified version of the unit commitment problem in this tutorial just to make it easier to follow. MIPLearn can also handle realistic, large-scale versions of this problem.\n",
"\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "a5fd33f6",
"metadata": {},
"source": [
"Next, let us convert this abstract mathematical formulation into a concrete optimization model, using Python and Pyomo. We start by defining a data class `UnitCommitmentData`, which holds all the input data."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "22a67170-10b4-43d3-8708-014d91141e73",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:18:25.442346786Z",
"start_time": "2023-06-06T20:18:25.329017476Z"
},
"tags": []
},
"outputs": [],
"source": [
"from dataclasses import dataclass\n",
"from typing import List\n",
"\n",
"import numpy as np\n",
"\n",
"\n",
"@dataclass\n",
"class UnitCommitmentData:\n",
" demand: float\n",
" pmin: List[float]\n",
" pmax: List[float]\n",
" cfix: List[float]\n",
" cvar: List[float]"
]
},
{
"cell_type": "markdown",
"id": "29f55efa-0751-465a-9b0a-a821d46a3d40",
"metadata": {},
"source": [
"Next, we write a `build_uc_model` function, which converts the input data into a concrete Pyomo model. The function accepts `UnitCommitmentData`, the data structure we previously defined, or the path to a compressed pickle file containing this data."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "2f67032f-0d74-4317-b45c-19da0ec859e9",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:48:05.953902842Z",
"start_time": "2023-06-06T20:48:05.909747925Z"
}
},
"outputs": [],
"source": [
"import gurobipy as gp\n",
"from gurobipy import GRB, quicksum\n",
"from typing import Union\n",
"from miplearn.io import read_pkl_gz\n",
"from miplearn.solvers.gurobi import GurobiModel\n",
"\n",
"def build_uc_model(data: Union[str, UnitCommitmentData]) -> GurobiModel:\n",
" if isinstance(data, str):\n",
" data = read_pkl_gz(data)\n",
"\n",
" model = gp.Model()\n",
" n = len(data.pmin)\n",
" x = model._x = model.addVars(n, vtype=GRB.BINARY, name=\"x\")\n",
" y = model._y = model.addVars(n, name=\"y\")\n",
" model.setObjective(\n",
" quicksum(\n",
" data.cfix[i] * x[i] + data.cvar[i] * y[i] for i in range(n)\n",
" )\n",
" )\n",
" model.addConstrs(y[i] <= data.pmax[i] * x[i] for i in range(n))\n",
" model.addConstrs(y[i] >= data.pmin[i] * x[i] for i in range(n))\n",
" model.addConstr(quicksum(y[i] for i in range(n)) == data.demand)\n",
" return GurobiModel(model)"
]
},
{
"cell_type": "markdown",
"id": "c22714a3",
"metadata": {},
"source": [
"At this point, we can already use Pyomo 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:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "2a896f47",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:49:14.266758244Z",
"start_time": "2023-06-06T20:49:14.223514806Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Restricted license - for non-production use only - expires 2024-10-28\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 7 rows, 6 columns and 15 nonzeros\n",
"Model fingerprint: 0x58dfdd53\n",
"Variable types: 3 continuous, 3 integer (3 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 7e+01]\n",
" Objective range [2e+00, 7e+02]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [1e+02, 1e+02]\n",
"Presolve removed 2 rows and 1 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 5 rows, 5 columns, 13 nonzeros\n",
"Variable types: 0 continuous, 5 integer (3 binary)\n",
"Found heuristic solution: objective 1400.0000000\n",
"\n",
"Root relaxation: objective 1.035000e+03, 3 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 1035.00000 0 1 1400.00000 1035.00000 26.1% - 0s\n",
" 0 0 1105.71429 0 1 1400.00000 1105.71429 21.0% - 0s\n",
"* 0 0 0 1320.0000000 1320.00000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (5 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 2: 1320 1400 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 1.320000000000e+03, best bound 1.320000000000e+03, gap 0.0000%\n",
"obj = 1320.0\n",
"x = [-0.0, 1.0, 1.0]\n",
"y = [0.0, 60.0, 40.0]\n"
]
}
],
"source": [
"model = build_uc_model(\n",
" UnitCommitmentData(\n",
" demand=100.0,\n",
" pmin=[10, 20, 30],\n",
" pmax=[50, 60, 70],\n",
" cfix=[700, 600, 500],\n",
" cvar=[1.5, 2.0, 2.5],\n",
" )\n",
")\n",
"\n",
"model.optimize()\n",
"print(\"obj =\", model.inner.objVal)\n",
"print(\"x =\", [model.inner._x[i].x for i in range(3)])\n",
"print(\"y =\", [model.inner._y[i].x for i in range(3)])"
]
},
{
"cell_type": "markdown",
"id": "41b03bbc",
"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."
]
},
{
"cell_type": "markdown",
"id": "01f576e1-1790-425e-9e5c-9fa07b6f4c26",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
" \n",
"Note\n",
"\n",
"- In the example above, `GurobiModel` is just a thin wrapper around a standard Gurobi model. This wrapper allows MIPLearn to be solver- and modeling-language-agnostic. The wrapper provides only a few basic methods, such as `optimize`. For more control, and to query the solution, the original Gurobi model can be accessed through `model.inner`, as illustrated above.\n",
"- To ensure training data consistency, MIPLearn requires all decision variables to have names.\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "cf60c1dd",
"metadata": {},
"source": [
"## Generating training data\n",
"\n",
"Although Gurobi could solve the small example above in a fraction of a second, it gets slower for larger and more complex versions of the problem. If this is a problem that needs to be solved frequently, as it is often the case in practice, it could make sense to spend some time upfront generating a **trained** solver, which can optimize new instances (similar to the ones it was trained on) faster.\n",
"\n",
"In the following, we will use MIPLearn to train machine learning models that is able to predict the optimal solution for instances that follow a given probability distribution, then it will provide this predicted solution to Gurobi as a warm start. Before we can train the model, we need to collect training data by solving a large number of instances. In real-world situations, we may construct these training instances based on historical data. In this tutorial, we will construct them using a random instance generator:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "5eb09fab",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:49:22.758192368Z",
"start_time": "2023-06-06T20:49:22.724784572Z"
}
},
"outputs": [],
"source": [
"from scipy.stats import uniform\n",
"from typing import List\n",
"import random\n",
"\n",
"\n",
"def random_uc_data(samples: int, n: int, seed: int = 42) -> List[UnitCommitmentData]:\n",
" random.seed(seed)\n",
" np.random.seed(seed)\n",
" pmin = uniform(loc=100_000.0, scale=400_000.0).rvs(n)\n",
" pmax = pmin * uniform(loc=2.0, scale=2.5).rvs(n)\n",
" cfix = pmin * uniform(loc=100.0, scale=25.0).rvs(n)\n",
" cvar = uniform(loc=1.25, scale=0.25).rvs(n)\n",
" return [\n",
" UnitCommitmentData(\n",
" demand=pmax.sum() * uniform(loc=0.5, scale=0.25).rvs(),\n",
" pmin=pmin,\n",
" pmax=pmax,\n",
" cfix=cfix,\n",
" cvar=cvar,\n",
" )\n",
" for _ in range(samples)\n",
" ]"
]
},
{
"cell_type": "markdown",
"id": "3a03a7ac",
"metadata": {},
"source": [
"In this example, for simplicity, only the demands change from one instance to the next. We could also have randomized the costs, production limits or even the number of units. 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",
"\n",
"Now we generate 500 instances of this problem, each one with 50 generators, and we use 450 of these instances for training. After generating the instances, we write them to individual files. MIPLearn uses files during the training process because, for large-scale optimization problems, it is often impractical to hold in memory the entire training data, as well as the concrete Pyomo models. Files also make it much easier to solve multiple instances simultaneously, potentially on multiple machines. The code below generates the files `uc/train/00000.pkl.gz`, `uc/train/00001.pkl.gz`, etc., which contain the input data in compressed (gzipped) pickle format."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "6156752c",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:49:24.811192929Z",
"start_time": "2023-06-06T20:49:24.575639142Z"
}
},
"outputs": [],
"source": [
"from miplearn.io import write_pkl_gz\n",
"\n",
"data = random_uc_data(samples=500, n=500)\n",
"train_data = write_pkl_gz(data[0:450], \"uc/train\")\n",
"test_data = write_pkl_gz(data[450:500], \"uc/test\")"
]
},
{
"cell_type": "markdown",
"id": "b17af877",
"metadata": {},
"source": [
"Finally, we use `BasicCollector` to collect the optimal solutions and other useful training data for all training instances. The data is stored in HDF5 files `uc/train/00000.h5`, `uc/train/00001.h5`, etc. The optimization models are also exported to compressed MPS files `uc/train/00000.mps.gz`, `uc/train/00001.mps.gz`, etc."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "7623f002",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:49:34.936729253Z",
"start_time": "2023-06-06T20:49:25.936126612Z"
}
},
"outputs": [],
"source": [
"from miplearn.collectors.basic import BasicCollector\n",
"\n",
"bc = BasicCollector()\n",
"bc.collect(train_data, build_uc_model, n_jobs=4)"
]
},
{
"cell_type": "markdown",
"id": "c42b1be1-9723-4827-82d8-974afa51ef9f",
"metadata": {},
"source": [
"## Training and solving test instances"
]
},
{
"cell_type": "markdown",
"id": "a33c6aa4-f0b8-4ccb-9935-01f7d7de2a1c",
"metadata": {},
"source": [
"With training data in hand, we can now design and train a machine learning model to accelerate solver performance. In this tutorial, for illustration purposes, we will use ML to generate a good warm start using $k$-nearest neighbors. More specifically, the strategy is to:\n",
"\n",
"1. Memorize the optimal solutions of all training instances;\n",
"2. Given a test instance, find the 25 most similar training instances, based on constraint right-hand sides;\n",
"3. Merge their optimal solutions into a single partial solution; specifically, only assign values to the binary variables that agree unanimously.\n",
"4. Provide this partial solution to the solver as a warm start.\n",
"\n",
"This simple strategy can be implemented as shown below, using `MemorizingPrimalComponent`. For more advanced strategies, and for the usage of more advanced classifiers, see the user guide."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "435f7bf8-4b09-4889-b1ec-b7b56e7d8ed2",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:49:38.997939600Z",
"start_time": "2023-06-06T20:49:38.968261432Z"
}
},
"outputs": [],
"source": [
"from sklearn.neighbors import KNeighborsClassifier\n",
"from miplearn.components.primal.actions import SetWarmStart\n",
"from miplearn.components.primal.mem import (\n",
" MemorizingPrimalComponent,\n",
" MergeTopSolutions,\n",
")\n",
"from miplearn.extractors.fields import H5FieldsExtractor\n",
"\n",
"comp = MemorizingPrimalComponent(\n",
" clf=KNeighborsClassifier(n_neighbors=25),\n",
" extractor=H5FieldsExtractor(\n",
" instance_fields=[\"static_constr_rhs\"],\n",
" ),\n",
" constructor=MergeTopSolutions(25, [0.0, 1.0]),\n",
" action=SetWarmStart(),\n",
")"
]
},
{
"cell_type": "markdown",
"id": "9536e7e4-0b0d-49b0-bebd-4a848f839e94",
"metadata": {},
"source": [
"Having defined the ML strategy, we next construct `LearningSolver`, train the ML component and optimize one of the test instances."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "9d13dd50-3dcf-4673-a757-6f44dcc0dedf",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:49:42.072345411Z",
"start_time": "2023-06-06T20:49:41.294040974Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0xa8b70287\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
" 0 6.6166537e+09 5.648803e+04 0.000000e+00 0s\n",
" 1 8.2906219e+09 0.000000e+00 0.000000e+00 0s\n",
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.290621916e+09\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x4ccd7ae3\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"\n",
"User MIP start produced solution with objective 8.30129e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29184e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29146e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29146e+09 (0.01s)\n",
"Loaded user MIP start with objective 8.29146e+09\n",
"\n",
"Presolve time: 0.00s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
"Root relaxation: objective 8.290622e+09, 512 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 8.2906e+09 0 1 8.2915e+09 8.2906e+09 0.01% - 0s\n",
"\n",
"Cutting planes:\n",
" Cover: 1\n",
" Flow cover: 2\n",
"\n",
"Explored 1 nodes (512 simplex iterations) in 0.07 seconds (0.01 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 3: 8.29146e+09 8.29184e+09 8.30129e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 8.291459497797e+09, best bound 8.290645029670e+09, gap 0.0098%\n"
]
}
],
"source": [
"from miplearn.solvers.learning import LearningSolver\n",
"\n",
"solver_ml = LearningSolver(components=[comp])\n",
"solver_ml.fit(train_data)\n",
"solver_ml.optimize(test_data[0], build_uc_model);"
]
},
{
"cell_type": "markdown",
"id": "61da6dad-7f56-4edb-aa26-c00eb5f946c0",
"metadata": {},
"source": [
"By examining the solve log above, specifically the line `Loaded user MIP start with objective...`, we can see that MIPLearn was able to construct an initial solution which turned out to be very close to the optimal solution to the problem. Now let us repeat the code above, but a solver which does not apply any ML strategies. Note that our previously-defined component is not provided."
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "2ff391ed-e855-4228-aa09-a7641d8c2893",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:49:44.012782276Z",
"start_time": "2023-06-06T20:49:43.813974362Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0xa8b70287\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
" 0 6.6166537e+09 5.648803e+04 0.000000e+00 0s\n",
" 1 8.2906219e+09 0.000000e+00 0.000000e+00 0s\n",
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.290621916e+09\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x4cbbf7c7\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve time: 0.00s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Found heuristic solution: objective 9.757128e+09\n",
"\n",
"Root relaxation: objective 8.290622e+09, 512 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 8.2906e+09 0 1 9.7571e+09 8.2906e+09 15.0% - 0s\n",
"H 0 0 8.298273e+09 8.2906e+09 0.09% - 0s\n",
" 0 0 8.2907e+09 0 4 8.2983e+09 8.2907e+09 0.09% - 0s\n",
" 0 0 8.2907e+09 0 1 8.2983e+09 8.2907e+09 0.09% - 0s\n",
" 0 0 8.2907e+09 0 4 8.2983e+09 8.2907e+09 0.09% - 0s\n",
"H 0 0 8.293980e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2907e+09 0 5 8.2940e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2907e+09 0 1 8.2940e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2907e+09 0 2 8.2940e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2908e+09 0 1 8.2940e+09 8.2908e+09 0.04% - 0s\n",
" 0 0 8.2908e+09 0 4 8.2940e+09 8.2908e+09 0.04% - 0s\n",
" 0 0 8.2908e+09 0 4 8.2940e+09 8.2908e+09 0.04% - 0s\n",
"H 0 0 8.291465e+09 8.2908e+09 0.01% - 0s\n",
"\n",
"Cutting planes:\n",
" Gomory: 2\n",
" MIR: 1\n",
"\n",
"Explored 1 nodes (1031 simplex iterations) in 0.07 seconds (0.03 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 4: 8.29147e+09 8.29398e+09 8.29827e+09 9.75713e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 8.291465302389e+09, best bound 8.290781665333e+09, gap 0.0082%\n"
]
}
],
"source": [
"solver_baseline = LearningSolver(components=[])\n",
"solver_baseline.fit(train_data)\n",
"solver_baseline.optimize(test_data[0], build_uc_model);"
]
},
{
"cell_type": "markdown",
"id": "b6d37b88-9fcc-43ee-ac1e-2a7b1e51a266",
"metadata": {},
"source": [
"In the log above, the `MIP start` line is missing, and Gurobi had to start with a significantly inferior initial solution. The solver was still able to find the optimal solution at the end, but it required using its own internal heuristic procedures. In this example, because we solve very small optimization problems, there was almost no difference in terms of running time, but the difference can be significant for larger problems."
]
},
{
"cell_type": "markdown",
"id": "eec97f06",
"metadata": {
"tags": []
},
"source": [
"## Accessing the solution\n",
"\n",
"In the example above, we used `LearningSolver.solve` together with data files to solve both the training and the test instances. The optimal solutions were saved to HDF5 files in the train/test folders, and could be retrieved by reading theses files, but that is not very convenient. In the following example, we show how to build and solve a Pyomo model entirely in-memory, using our trained solver."
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "67a6cd18",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:50:12.869892930Z",
"start_time": "2023-06-06T20:50:12.509410473Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x19042f12\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
" 0 6.5917580e+09 5.627453e+04 0.000000e+00 0s\n",
" 1 8.2535968e+09 0.000000e+00 0.000000e+00 0s\n",
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.253596777e+09\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x8ee64638\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"\n",
"User MIP start produced solution with objective 8.25814e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25512e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.04s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.04s)\n",
"Loaded user MIP start with objective 8.25459e+09\n",
"\n",
"Presolve time: 0.01s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
"Root relaxation: objective 8.253597e+09, 512 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 8.2536e+09 0 1 8.2546e+09 8.2536e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 3 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 1 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 4 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 4 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2538e+09 0 4 8.2546e+09 8.2538e+09 0.01% - 0s\n",
" 0 0 8.2538e+09 0 5 8.2546e+09 8.2538e+09 0.01% - 0s\n",
" 0 0 8.2538e+09 0 6 8.2546e+09 8.2538e+09 0.01% - 0s\n",
"\n",
"Cutting planes:\n",
" Cover: 1\n",
" MIR: 2\n",
" StrongCG: 1\n",
" Flow cover: 1\n",
"\n",
"Explored 1 nodes (575 simplex iterations) in 0.12 seconds (0.01 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 3: 8.25459e+09 8.25512e+09 8.25814e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 8.254590409970e+09, best bound 8.253768093811e+09, gap 0.0100%\n",
"obj = 8254590409.969726\n",
"x = [1.0, 1.0, 0.0]\n",
"y = [935662.0949263407, 1604270.0218116897, 0.0]\n"
]
}
],
"source": [
"data = random_uc_data(samples=1, n=500)[0]\n",
"model = build_uc_model(data)\n",
"solver_ml.optimize(model)\n",
"print(\"obj =\", model.inner.objVal)\n",
"print(\"x =\", [model.inner._x[i].x for i in range(3)])\n",
"print(\"y =\", [model.inner._y[i].x for i in range(3)])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5593d23a-83bd-4e16-8253-6300f5e3f63b",
"metadata": {},
"outputs": [],
"source": []
}
],
"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.9.16"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

@ -0,0 +1,885 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>2. Getting started (Gurobipy) &#8212; MIPLearn 0.3</title>
<link href="../../_static/css/theme.css" rel="stylesheet" />
<link href="../../_static/css/index.c5995385ac14fb8791e8eb36b4908be2.css" rel="stylesheet" />
<link rel="stylesheet"
href="../../_static/vendor/fontawesome/5.13.0/css/all.min.css">
<link rel="preload" as="font" type="font/woff2" crossorigin
href="../../_static/vendor/fontawesome/5.13.0/webfonts/fa-solid-900.woff2">
<link rel="preload" as="font" type="font/woff2" crossorigin
href="../../_static/vendor/fontawesome/5.13.0/webfonts/fa-brands-400.woff2">
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../_static/sphinx-book-theme.acff12b8f9c144ce68a297486a2fa670.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/custom.css" />
<link rel="preload" as="script" href="../../_static/js/index.1c5a1a01449ed65a7b51.js">
<script id="documentation_options" data-url_root="../../" src="../../_static/documentation_options.js"></script>
<script src="../../_static/jquery.js"></script>
<script src="../../_static/underscore.js"></script>
<script src="../../_static/doctools.js"></script>
<script crossorigin="anonymous" integrity="sha256-Ae2Vz/4ePdIu6ZyI/5ZGsYnb+m0JlOmKPjt6XZ9JJkA=" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"></script>
<script src="../../_static/sphinx-book-theme.12a9622fbb08dcb3a2a40b2c02b83a57.js"></script>
<script async="async" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/x-mathjax-config">MathJax.Hub.Config({"tex2jax": {"inlineMath": [["\\(", "\\)"]], "displayMath": [["\\[", "\\]"]], "processRefs": false, "processEnvironments": false}})</script>
<link rel="index" title="Index" href="../../genindex/" />
<link rel="search" title="Search" href="../../search/" />
<link rel="next" title="3. Getting started (JuMP)" href="../getting-started-jump/" />
<link rel="prev" title="1. Getting started (Pyomo)" href="../getting-started-pyomo/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="docsearch:language" content="en" />
</head>
<body data-spy="scroll" data-target="#bd-toc-nav" data-offset="80">
<div class="container-fluid" id="banner"></div>
<div class="container-xl">
<div class="row">
<div class="col-12 col-md-3 bd-sidebar site-navigation show" id="site-navigation">
<div class="navbar-brand-box">
<a class="navbar-brand text-wrap" href="../../">
<h1 class="site-logo" id="site-title">MIPLearn 0.3</h1>
</a>
</div><form class="bd-search d-flex align-items-center" action="../../search/" method="get">
<i class="icon fas fa-search"></i>
<input type="search" class="form-control" name="q" id="search-input" placeholder="Search the docs ..." aria-label="Search the docs ..." autocomplete="off" >
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="current nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1 current active">
<a class="current reference internal" href="#">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../getting-started-jump/">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../guide/problems/">
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/collectors/">
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/features/">
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/primal/">
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/solvers/">
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
Python API Reference
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../api/problems/">
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/collectors/">
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/components/">
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/solvers/">
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/helpers/">
13. Helpers
</a>
</li>
</ul>
</div>
</nav> <!-- To handle the deprecated key -->
</div>
<main class="col py-md-3 pl-md-4 bd-content overflow-auto" role="main">
<div class="topbar container-xl fixed-top">
<div class="topbar-contents row">
<div class="col-12 col-md-3 bd-topbar-whitespace site-navigation show"></div>
<div class="col pl-md-4 topbar-main">
<button id="navbar-toggler" class="navbar-toggler ml-0" type="button" data-toggle="collapse"
data-toggle="tooltip" data-placement="bottom" data-target=".site-navigation" aria-controls="navbar-menu"
aria-expanded="true" aria-label="Toggle navigation" aria-controls="site-navigation"
title="Toggle navigation" data-toggle="tooltip" data-placement="left">
<i class="fas fa-bars"></i>
<i class="fas fa-arrow-left"></i>
<i class="fas fa-arrow-up"></i>
</button>
<div class="dropdown-buttons-trigger">
<button id="dropdown-buttons-trigger" class="btn btn-secondary topbarbtn" aria-label="Download this page"><i
class="fas fa-download"></i></button>
<div class="dropdown-buttons">
<!-- ipynb file if we had a myst markdown file -->
<!-- Download raw file -->
<a class="dropdown-buttons" href="../../_sources/tutorials/getting-started-gurobipy.ipynb.txt"><button type="button"
class="btn btn-secondary topbarbtn" title="Download source file" data-toggle="tooltip"
data-placement="left">.ipynb</button></a>
<!-- Download PDF via print -->
<button type="button" id="download-print" class="btn btn-secondary topbarbtn" title="Print to PDF"
onClick="window.print()" data-toggle="tooltip" data-placement="left">.pdf</button>
</div>
</div>
<!-- Source interaction buttons -->
<!-- Full screen (wrap in <a> to have style consistency -->
<a class="full-screen-button"><button type="button" class="btn btn-secondary topbarbtn" data-toggle="tooltip"
data-placement="bottom" onclick="toggleFullScreen()" aria-label="Fullscreen mode"
title="Fullscreen mode"><i
class="fas fa-expand"></i></button></a>
<!-- Launch buttons -->
</div>
<!-- Table of contents -->
<div class="d-none d-md-block col-md-2 bd-toc show">
<div class="tocsection onthispage pt-5 pb-3">
<i class="fas fa-list"></i> Contents
</div>
<nav id="bd-toc-nav">
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Introduction">
2.1. Introduction
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Installation">
2.2. Installation
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Modeling-a-simple-optimization-problem">
2.3. Modeling a simple optimization problem
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Generating-training-data">
2.4. Generating training data
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Training-and-solving-test-instances">
2.5. Training and solving test instances
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Accessing-the-solution">
2.6. Accessing the solution
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div id="main-content" class="row">
<div class="col-12 col-md-9 pl-md-3 pr-md-0">
<div>
<div class="section" id="Getting-started-(Gurobipy)">
<h1><span class="section-number">2. </span>Getting started (Gurobipy)<a class="headerlink" href="#Getting-started-(Gurobipy)" title="Permalink to this headline"></a></h1>
<div class="section" id="Introduction">
<h2><span class="section-number">2.1. </span>Introduction<a class="headerlink" href="#Introduction" title="Permalink to this headline"></a></h2>
<p><strong>MIPLearn</strong> is an open source framework that uses machine learning (ML) to accelerate the performance of mixed-integer programming solvers (e.g. Gurobi, CPLEX, XPRESS). In this tutorial, we will:</p>
<ol class="arabic simple">
<li><p>Install the Python/Gurobipy version of MIPLearn</p></li>
<li><p>Model a simple optimization problem using Gurobipy</p></li>
<li><p>Generate training data and train the ML models</p></li>
<li><p>Use the ML models together Gurobi to solve new instances</p></li>
</ol>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>The Python/Gurobipy version of MIPLearn is only compatible with the Gurobi Optimizer. For broader solver compatibility, see the Python/Pyomo and Julia/JuMP versions of the package.</p>
</div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>MIPLearn is still in early development stage. If run into any bugs or issues, please submit a bug report in our GitHub repository. Comments, suggestions and pull requests are also very welcome!</p>
</div>
</div>
<div class="section" id="Installation">
<h2><span class="section-number">2.2. </span>Installation<a class="headerlink" href="#Installation" title="Permalink to this headline"></a></h2>
<p>MIPLearn is available in two versions:</p>
<ul class="simple">
<li><p>Python version, compatible with the Pyomo and Gurobipy modeling languages,</p></li>
<li><p>Julia version, compatible with the JuMP modeling language.</p></li>
</ul>
<p>In this tutorial, we will demonstrate how to use and install the Python/Gurobipy version of the package. The first step is to install Python 3.8+ in your computer. See the <a class="reference external" href="https://www.python.org/downloads/">official Python website for more instructions</a>. After Python is installed, we proceed to install MIPLearn using <code class="docutils literal notranslate"><span class="pre">pip</span></code>:</p>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[1]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># !pip install MIPLearn==0.3.0</span>
</pre></div>
</div>
</div>
<p>In addition to MIPLearn itself, we will also install Gurobi 10.0, a state-of-the-art commercial MILP solver. This step also install a demo license for Gurobi, which should able to solve the small optimization problems in this tutorial. A license is required for solving larger-scale problems.</p>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[2]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="o">!</span>pip install <span class="s1">&#39;gurobipy&gt;=10,&lt;10.1&#39;</span>
</pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area docutils container">
<div class="highlight"><pre>
Requirement already satisfied: gurobipy&lt;10.1,&gt;=10 in /home/axavier/Software/anaconda3/envs/miplearn/lib/python3.8/site-packages (10.0.1)
</pre></div></div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>In the code above, we install specific version of all packages to ensure that this tutorial keeps running in the future, even when newer (and possibly incompatible) versions of the packages are released. This is usually a recommended practice for all Python projects.</p>
</div>
</div>
<div class="section" id="Modeling-a-simple-optimization-problem">
<h2><span class="section-number">2.3. </span>Modeling a simple optimization problem<a class="headerlink" href="#Modeling-a-simple-optimization-problem" title="Permalink to this headline"></a></h2>
<p>To illustrate how can MIPLearn be used, we will model and solve a small optimization problem related to power systems optimization. The problem we discuss below is a simplification of the <strong>unit commitment problem,</strong> a practical optimization problem solved daily by electric grid operators around the world.</p>
<p>Suppose that a utility company needs to decide which electrical generators should be online at each hour of the day, as well as how much power should each generator produce. More specifically, assume that the company owns <span class="math notranslate nohighlight">\(n\)</span> generators, denoted by <span class="math notranslate nohighlight">\(g_1, \ldots, g_n\)</span>. Each generator can either be online or offline. An online generator <span class="math notranslate nohighlight">\(g_i\)</span> can produce between <span class="math notranslate nohighlight">\(p^\text{min}_i\)</span> to <span class="math notranslate nohighlight">\(p^\text{max}_i\)</span> megawatts of power, and it costs the company
<span class="math notranslate nohighlight">\(c^\text{fix}_i + c^\text{var}_i y_i\)</span>, where <span class="math notranslate nohighlight">\(y_i\)</span> is the amount of power produced. An offline generator produces nothing and costs nothing. The total amount of power to be produced needs to be exactly equal to the total demand <span class="math notranslate nohighlight">\(d\)</span> (in megawatts).</p>
<p>This simple problem can be modeled as a <em>mixed-integer linear optimization</em> problem as follows. For each generator <span class="math notranslate nohighlight">\(g_i\)</span>, let <span class="math notranslate nohighlight">\(x_i \in \{0,1\}\)</span> be a decision variable indicating whether <span class="math notranslate nohighlight">\(g_i\)</span> is online, and let <span class="math notranslate nohighlight">\(y_i \geq 0\)</span> be a decision variable indicating how much power does <span class="math notranslate nohighlight">\(g_i\)</span> produce. The problem is then given by:</p>
<div class="math notranslate nohighlight">
\[\begin{split}\begin{align}
\text{minimize } \quad &amp; \sum_{i=1}^n \left( c^\text{fix}_i x_i + c^\text{var}_i y_i \right) \\
\text{subject to } \quad &amp; y_i \leq p^\text{max}_i x_i &amp; i=1,\ldots,n \\
&amp; y_i \geq p^\text{min}_i x_i &amp; i=1,\ldots,n \\
&amp; \sum_{i=1}^n y_i = d \\
&amp; x_i \in \{0,1\} &amp; i=1,\ldots,n \\
&amp; y_i \geq 0 &amp; i=1,\ldots,n
\end{align}\end{split}\]</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>We use a simplified version of the unit commitment problem in this tutorial just to make it easier to follow. MIPLearn can also handle realistic, large-scale versions of this problem.</p>
</div>
<p>Next, let us convert this abstract mathematical formulation into a concrete optimization model, using Python and Pyomo. We start by defining a data class <code class="docutils literal notranslate"><span class="pre">UnitCommitmentData</span></code>, which holds all the input data.</p>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[3]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="nd">@dataclass</span>
<span class="k">class</span> <span class="nc">UnitCommitmentData</span><span class="p">:</span>
<span class="n">demand</span><span class="p">:</span> <span class="nb">float</span>
<span class="n">pmin</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">float</span><span class="p">]</span>
<span class="n">pmax</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">float</span><span class="p">]</span>
<span class="n">cfix</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">float</span><span class="p">]</span>
<span class="n">cvar</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">float</span><span class="p">]</span>
</pre></div>
</div>
</div>
<p>Next, we write a <code class="docutils literal notranslate"><span class="pre">build_uc_model</span></code> function, which converts the input data into a concrete Pyomo model. The function accepts <code class="docutils literal notranslate"><span class="pre">UnitCommitmentData</span></code>, the data structure we previously defined, or the path to a compressed pickle file containing this data.</p>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[4]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">gurobipy</span> <span class="k">as</span> <span class="nn">gp</span>
<span class="kn">from</span> <span class="nn">gurobipy</span> <span class="kn">import</span> <span class="n">GRB</span><span class="p">,</span> <span class="n">quicksum</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Union</span>
<span class="kn">from</span> <span class="nn">miplearn.io</span> <span class="kn">import</span> <span class="n">read_pkl_gz</span>
<span class="kn">from</span> <span class="nn">miplearn.solvers.gurobi</span> <span class="kn">import</span> <span class="n">GurobiModel</span>
<span class="k">def</span> <span class="nf">build_uc_model</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">UnitCommitmentData</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">GurobiModel</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">read_pkl_gz</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">gp</span><span class="o">.</span><span class="n">Model</span><span class="p">()</span>
<span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">pmin</span><span class="p">)</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">_x</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">addVars</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">vtype</span><span class="o">=</span><span class="n">GRB</span><span class="o">.</span><span class="n">BINARY</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;x&quot;</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">_y</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">addVars</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;y&quot;</span><span class="p">)</span>
<span class="n">model</span><span class="o">.</span><span class="n">setObjective</span><span class="p">(</span>
<span class="n">quicksum</span><span class="p">(</span>
<span class="n">data</span><span class="o">.</span><span class="n">cfix</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">x</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">data</span><span class="o">.</span><span class="n">cvar</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">y</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="n">model</span><span class="o">.</span><span class="n">addConstrs</span><span class="p">(</span><span class="n">y</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">data</span><span class="o">.</span><span class="n">pmax</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">x</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">))</span>
<span class="n">model</span><span class="o">.</span><span class="n">addConstrs</span><span class="p">(</span><span class="n">y</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">data</span><span class="o">.</span><span class="n">pmin</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">x</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">))</span>
<span class="n">model</span><span class="o">.</span><span class="n">addConstr</span><span class="p">(</span><span class="n">quicksum</span><span class="p">(</span><span class="n">y</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">))</span> <span class="o">==</span> <span class="n">data</span><span class="o">.</span><span class="n">demand</span><span class="p">)</span>
<span class="k">return</span> <span class="n">GurobiModel</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p>At this point, we can already use Pyomo 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:</p>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[5]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">model</span> <span class="o">=</span> <span class="n">build_uc_model</span><span class="p">(</span>
<span class="n">UnitCommitmentData</span><span class="p">(</span>
<span class="n">demand</span><span class="o">=</span><span class="mf">100.0</span><span class="p">,</span>
<span class="n">pmin</span><span class="o">=</span><span class="p">[</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">30</span><span class="p">],</span>
<span class="n">pmax</span><span class="o">=</span><span class="p">[</span><span class="mi">50</span><span class="p">,</span> <span class="mi">60</span><span class="p">,</span> <span class="mi">70</span><span class="p">],</span>
<span class="n">cfix</span><span class="o">=</span><span class="p">[</span><span class="mi">700</span><span class="p">,</span> <span class="mi">600</span><span class="p">,</span> <span class="mi">500</span><span class="p">],</span>
<span class="n">cvar</span><span class="o">=</span><span class="p">[</span><span class="mf">1.5</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">2.5</span><span class="p">],</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="n">model</span><span class="o">.</span><span class="n">optimize</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;obj =&quot;</span><span class="p">,</span> <span class="n">model</span><span class="o">.</span><span class="n">inner</span><span class="o">.</span><span class="n">objVal</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;x =&quot;</span><span class="p">,</span> <span class="p">[</span><span class="n">model</span><span class="o">.</span><span class="n">inner</span><span class="o">.</span><span class="n">_x</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">x</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">)])</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;y =&quot;</span><span class="p">,</span> <span class="p">[</span><span class="n">model</span><span class="o">.</span><span class="n">inner</span><span class="o">.</span><span class="n">_y</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">x</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">)])</span>
</pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area docutils container">
<div class="highlight"><pre>
Restricted license - for non-production use only - expires 2024-10-28
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]
Thread count: 6 physical cores, 12 logical processors, using up to 12 threads
Optimize a model with 7 rows, 6 columns and 15 nonzeros
Model fingerprint: 0x58dfdd53
Variable types: 3 continuous, 3 integer (3 binary)
Coefficient statistics:
Matrix range [1e+00, 7e+01]
Objective range [2e+00, 7e+02]
Bounds range [1e+00, 1e+00]
RHS range [1e+02, 1e+02]
Presolve removed 2 rows and 1 columns
Presolve time: 0.00s
Presolved: 5 rows, 5 columns, 13 nonzeros
Variable types: 0 continuous, 5 integer (3 binary)
Found heuristic solution: objective 1400.0000000
Root relaxation: objective 1.035000e+03, 3 iterations, 0.00 seconds (0.00 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
0 0 1035.00000 0 1 1400.00000 1035.00000 26.1% - 0s
0 0 1105.71429 0 1 1400.00000 1105.71429 21.0% - 0s
* 0 0 0 1320.0000000 1320.00000 0.00% - 0s
Explored 1 nodes (5 simplex iterations) in 0.01 seconds (0.00 work units)
Thread count was 12 (of 12 available processors)
Solution count 2: 1320 1400
Optimal solution found (tolerance 1.00e-04)
Best objective 1.320000000000e+03, best bound 1.320000000000e+03, gap 0.0000%
obj = 1320.0
x = [-0.0, 1.0, 1.0]
y = [0.0, 60.0, 40.0]
</pre></div></div>
</div>
<p>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.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<ul class="simple">
<li><p>In the example above, <code class="docutils literal notranslate"><span class="pre">GurobiModel</span></code> is just a thin wrapper around a standard Gurobi model. This wrapper allows MIPLearn to be solver- and modeling-language-agnostic. The wrapper provides only a few basic methods, such as <code class="docutils literal notranslate"><span class="pre">optimize</span></code>. For more control, and to query the solution, the original Gurobi model can be accessed through <code class="docutils literal notranslate"><span class="pre">model.inner</span></code>, as illustrated above.</p></li>
<li><p>To ensure training data consistency, MIPLearn requires all decision variables to have names.</p></li>
</ul>
</div>
</div>
<div class="section" id="Generating-training-data">
<h2><span class="section-number">2.4. </span>Generating training data<a class="headerlink" href="#Generating-training-data" title="Permalink to this headline"></a></h2>
<p>Although Gurobi could solve the small example above in a fraction of a second, it gets slower for larger and more complex versions of the problem. If this is a problem that needs to be solved frequently, as it is often the case in practice, it could make sense to spend some time upfront generating a <strong>trained</strong> solver, which can optimize new instances (similar to the ones it was trained on) faster.</p>
<p>In the following, we will use MIPLearn to train machine learning models that is able to predict the optimal solution for instances that follow a given probability distribution, then it will provide this predicted solution to Gurobi as a warm start. Before we can train the model, we need to collect training data by solving a large number of instances. In real-world situations, we may construct these training instances based on historical data. In this tutorial, we will construct them using a
random instance generator:</p>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[6]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">scipy.stats</span> <span class="kn">import</span> <span class="n">uniform</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="k">def</span> <span class="nf">random_uc_data</span><span class="p">(</span><span class="n">samples</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">seed</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">42</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">UnitCommitmentData</span><span class="p">]:</span>
<span class="n">random</span><span class="o">.</span><span class="n">seed</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span>
<span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">seed</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span>
<span class="n">pmin</span> <span class="o">=</span> <span class="n">uniform</span><span class="p">(</span><span class="n">loc</span><span class="o">=</span><span class="mf">100_000.0</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="mf">400_000.0</span><span class="p">)</span><span class="o">.</span><span class="n">rvs</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
<span class="n">pmax</span> <span class="o">=</span> <span class="n">pmin</span> <span class="o">*</span> <span class="n">uniform</span><span class="p">(</span><span class="n">loc</span><span class="o">=</span><span class="mf">2.0</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="mf">2.5</span><span class="p">)</span><span class="o">.</span><span class="n">rvs</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
<span class="n">cfix</span> <span class="o">=</span> <span class="n">pmin</span> <span class="o">*</span> <span class="n">uniform</span><span class="p">(</span><span class="n">loc</span><span class="o">=</span><span class="mf">100.0</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="mf">25.0</span><span class="p">)</span><span class="o">.</span><span class="n">rvs</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
<span class="n">cvar</span> <span class="o">=</span> <span class="n">uniform</span><span class="p">(</span><span class="n">loc</span><span class="o">=</span><span class="mf">1.25</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="mf">0.25</span><span class="p">)</span><span class="o">.</span><span class="n">rvs</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
<span class="k">return</span> <span class="p">[</span>
<span class="n">UnitCommitmentData</span><span class="p">(</span>
<span class="n">demand</span><span class="o">=</span><span class="n">pmax</span><span class="o">.</span><span class="n">sum</span><span class="p">()</span> <span class="o">*</span> <span class="n">uniform</span><span class="p">(</span><span class="n">loc</span><span class="o">=</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="mf">0.25</span><span class="p">)</span><span class="o">.</span><span class="n">rvs</span><span class="p">(),</span>
<span class="n">pmin</span><span class="o">=</span><span class="n">pmin</span><span class="p">,</span>
<span class="n">pmax</span><span class="o">=</span><span class="n">pmax</span><span class="p">,</span>
<span class="n">cfix</span><span class="o">=</span><span class="n">cfix</span><span class="p">,</span>
<span class="n">cvar</span><span class="o">=</span><span class="n">cvar</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">samples</span><span class="p">)</span>
<span class="p">]</span>
</pre></div>
</div>
</div>
<p>In this example, for simplicity, only the demands change from one instance to the next. We could also have randomized the costs, production limits or even the number of units. The more randomization we have in the training data, however, the more challenging it is for the machine learning models to learn solution patterns.</p>
<p>Now we generate 500 instances of this problem, each one with 50 generators, and we use 450 of these instances for training. After generating the instances, we write them to individual files. MIPLearn uses files during the training process because, for large-scale optimization problems, it is often impractical to hold in memory the entire training data, as well as the concrete Pyomo models. Files also make it much easier to solve multiple instances simultaneously, potentially on multiple
machines. The code below generates the files <code class="docutils literal notranslate"><span class="pre">uc/train/00000.pkl.gz</span></code>, <code class="docutils literal notranslate"><span class="pre">uc/train/00001.pkl.gz</span></code>, etc., which contain the input data in compressed (gzipped) pickle format.</p>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[7]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">miplearn.io</span> <span class="kn">import</span> <span class="n">write_pkl_gz</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">random_uc_data</span><span class="p">(</span><span class="n">samples</span><span class="o">=</span><span class="mi">500</span><span class="p">,</span> <span class="n">n</span><span class="o">=</span><span class="mi">500</span><span class="p">)</span>
<span class="n">train_data</span> <span class="o">=</span> <span class="n">write_pkl_gz</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">450</span><span class="p">],</span> <span class="s2">&quot;uc/train&quot;</span><span class="p">)</span>
<span class="n">test_data</span> <span class="o">=</span> <span class="n">write_pkl_gz</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">450</span><span class="p">:</span><span class="mi">500</span><span class="p">],</span> <span class="s2">&quot;uc/test&quot;</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p>Finally, we use <code class="docutils literal notranslate"><span class="pre">BasicCollector</span></code> to collect the optimal solutions and other useful training data for all training instances. The data is stored in HDF5 files <code class="docutils literal notranslate"><span class="pre">uc/train/00000.h5</span></code>, <code class="docutils literal notranslate"><span class="pre">uc/train/00001.h5</span></code>, etc. The optimization models are also exported to compressed MPS files <code class="docutils literal notranslate"><span class="pre">uc/train/00000.mps.gz</span></code>, <code class="docutils literal notranslate"><span class="pre">uc/train/00001.mps.gz</span></code>, etc.</p>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[8]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">miplearn.collectors.basic</span> <span class="kn">import</span> <span class="n">BasicCollector</span>
<span class="n">bc</span> <span class="o">=</span> <span class="n">BasicCollector</span><span class="p">()</span>
<span class="n">bc</span><span class="o">.</span><span class="n">collect</span><span class="p">(</span><span class="n">train_data</span><span class="p">,</span> <span class="n">build_uc_model</span><span class="p">,</span> <span class="n">n_jobs</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="Training-and-solving-test-instances">
<h2><span class="section-number">2.5. </span>Training and solving test instances<a class="headerlink" href="#Training-and-solving-test-instances" title="Permalink to this headline"></a></h2>
<p>With training data in hand, we can now design and train a machine learning model to accelerate solver performance. In this tutorial, for illustration purposes, we will use ML to generate a good warm start using <span class="math notranslate nohighlight">\(k\)</span>-nearest neighbors. More specifically, the strategy is to:</p>
<ol class="arabic simple">
<li><p>Memorize the optimal solutions of all training instances;</p></li>
<li><p>Given a test instance, find the 25 most similar training instances, based on constraint right-hand sides;</p></li>
<li><p>Merge their optimal solutions into a single partial solution; specifically, only assign values to the binary variables that agree unanimously.</p></li>
<li><p>Provide this partial solution to the solver as a warm start.</p></li>
</ol>
<p>This simple strategy can be implemented as shown below, using <code class="docutils literal notranslate"><span class="pre">MemorizingPrimalComponent</span></code>. For more advanced strategies, and for the usage of more advanced classifiers, see the user guide.</p>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[9]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sklearn.neighbors</span> <span class="kn">import</span> <span class="n">KNeighborsClassifier</span>
<span class="kn">from</span> <span class="nn">miplearn.components.primal.actions</span> <span class="kn">import</span> <span class="n">SetWarmStart</span>
<span class="kn">from</span> <span class="nn">miplearn.components.primal.mem</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">MemorizingPrimalComponent</span><span class="p">,</span>
<span class="n">MergeTopSolutions</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">miplearn.extractors.fields</span> <span class="kn">import</span> <span class="n">H5FieldsExtractor</span>
<span class="n">comp</span> <span class="o">=</span> <span class="n">MemorizingPrimalComponent</span><span class="p">(</span>
<span class="n">clf</span><span class="o">=</span><span class="n">KNeighborsClassifier</span><span class="p">(</span><span class="n">n_neighbors</span><span class="o">=</span><span class="mi">25</span><span class="p">),</span>
<span class="n">extractor</span><span class="o">=</span><span class="n">H5FieldsExtractor</span><span class="p">(</span>
<span class="n">instance_fields</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;static_constr_rhs&quot;</span><span class="p">],</span>
<span class="p">),</span>
<span class="n">constructor</span><span class="o">=</span><span class="n">MergeTopSolutions</span><span class="p">(</span><span class="mi">25</span><span class="p">,</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">]),</span>
<span class="n">action</span><span class="o">=</span><span class="n">SetWarmStart</span><span class="p">(),</span>
<span class="p">)</span>
</pre></div>
</div>
</div>
<p>Having defined the ML strategy, we next construct <code class="docutils literal notranslate"><span class="pre">LearningSolver</span></code>, train the ML component and optimize one of the test instances.</p>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[10]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">miplearn.solvers.learning</span> <span class="kn">import</span> <span class="n">LearningSolver</span>
<span class="n">solver_ml</span> <span class="o">=</span> <span class="n">LearningSolver</span><span class="p">(</span><span class="n">components</span><span class="o">=</span><span class="p">[</span><span class="n">comp</span><span class="p">])</span>
<span class="n">solver_ml</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">train_data</span><span class="p">)</span>
<span class="n">solver_ml</span><span class="o">.</span><span class="n">optimize</span><span class="p">(</span><span class="n">test_data</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">build_uc_model</span><span class="p">);</span>
</pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area docutils container">
<div class="highlight"><pre>
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]
Thread count: 6 physical cores, 12 logical processors, using up to 12 threads
Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros
Model fingerprint: 0xa8b70287
Coefficient statistics:
Matrix range [1e+00, 2e+06]
Objective range [1e+00, 6e+07]
Bounds range [1e+00, 1e+00]
RHS range [3e+08, 3e+08]
Presolve removed 1000 rows and 500 columns
Presolve time: 0.00s
Presolved: 1 rows, 500 columns, 500 nonzeros
Iteration Objective Primal Inf. Dual Inf. Time
0 6.6166537e+09 5.648803e+04 0.000000e+00 0s
1 8.2906219e+09 0.000000e+00 0.000000e+00 0s
Solved in 1 iterations and 0.01 seconds (0.00 work units)
Optimal objective 8.290621916e+09
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]
Thread count: 6 physical cores, 12 logical processors, using up to 12 threads
Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros
Model fingerprint: 0x4ccd7ae3
Variable types: 500 continuous, 500 integer (500 binary)
Coefficient statistics:
Matrix range [1e+00, 2e+06]
Objective range [1e+00, 6e+07]
Bounds range [1e+00, 1e+00]
RHS range [3e+08, 3e+08]
User MIP start produced solution with objective 8.30129e+09 (0.01s)
User MIP start produced solution with objective 8.29184e+09 (0.01s)
User MIP start produced solution with objective 8.29146e+09 (0.01s)
User MIP start produced solution with objective 8.29146e+09 (0.01s)
Loaded user MIP start with objective 8.29146e+09
Presolve time: 0.00s
Presolved: 1001 rows, 1000 columns, 2500 nonzeros
Variable types: 500 continuous, 500 integer (500 binary)
Root relaxation: objective 8.290622e+09, 512 iterations, 0.00 seconds (0.00 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
0 0 8.2906e+09 0 1 8.2915e+09 8.2906e+09 0.01% - 0s
Cutting planes:
Cover: 1
Flow cover: 2
Explored 1 nodes (512 simplex iterations) in 0.07 seconds (0.01 work units)
Thread count was 12 (of 12 available processors)
Solution count 3: 8.29146e+09 8.29184e+09 8.30129e+09
Optimal solution found (tolerance 1.00e-04)
Best objective 8.291459497797e+09, best bound 8.290645029670e+09, gap 0.0098%
</pre></div></div>
</div>
<p>By examining the solve log above, specifically the line <code class="docutils literal notranslate"><span class="pre">Loaded</span> <span class="pre">user</span> <span class="pre">MIP</span> <span class="pre">start</span> <span class="pre">with</span> <span class="pre">objective...</span></code>, we can see that MIPLearn was able to construct an initial solution which turned out to be very close to the optimal solution to the problem. Now let us repeat the code above, but a solver which does not apply any ML strategies. Note that our previously-defined component is not provided.</p>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[11]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">solver_baseline</span> <span class="o">=</span> <span class="n">LearningSolver</span><span class="p">(</span><span class="n">components</span><span class="o">=</span><span class="p">[])</span>
<span class="n">solver_baseline</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">train_data</span><span class="p">)</span>
<span class="n">solver_baseline</span><span class="o">.</span><span class="n">optimize</span><span class="p">(</span><span class="n">test_data</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">build_uc_model</span><span class="p">);</span>
</pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area docutils container">
<div class="highlight"><pre>
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]
Thread count: 6 physical cores, 12 logical processors, using up to 12 threads
Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros
Model fingerprint: 0xa8b70287
Coefficient statistics:
Matrix range [1e+00, 2e+06]
Objective range [1e+00, 6e+07]
Bounds range [1e+00, 1e+00]
RHS range [3e+08, 3e+08]
Presolve removed 1000 rows and 500 columns
Presolve time: 0.00s
Presolved: 1 rows, 500 columns, 500 nonzeros
Iteration Objective Primal Inf. Dual Inf. Time
0 6.6166537e+09 5.648803e+04 0.000000e+00 0s
1 8.2906219e+09 0.000000e+00 0.000000e+00 0s
Solved in 1 iterations and 0.01 seconds (0.00 work units)
Optimal objective 8.290621916e+09
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]
Thread count: 6 physical cores, 12 logical processors, using up to 12 threads
Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros
Model fingerprint: 0x4cbbf7c7
Variable types: 500 continuous, 500 integer (500 binary)
Coefficient statistics:
Matrix range [1e+00, 2e+06]
Objective range [1e+00, 6e+07]
Bounds range [1e+00, 1e+00]
RHS range [3e+08, 3e+08]
Presolve time: 0.00s
Presolved: 1001 rows, 1000 columns, 2500 nonzeros
Variable types: 500 continuous, 500 integer (500 binary)
Found heuristic solution: objective 9.757128e+09
Root relaxation: objective 8.290622e+09, 512 iterations, 0.00 seconds (0.00 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
0 0 8.2906e+09 0 1 9.7571e+09 8.2906e+09 15.0% - 0s
H 0 0 8.298273e+09 8.2906e+09 0.09% - 0s
0 0 8.2907e+09 0 4 8.2983e+09 8.2907e+09 0.09% - 0s
0 0 8.2907e+09 0 1 8.2983e+09 8.2907e+09 0.09% - 0s
0 0 8.2907e+09 0 4 8.2983e+09 8.2907e+09 0.09% - 0s
H 0 0 8.293980e+09 8.2907e+09 0.04% - 0s
0 0 8.2907e+09 0 5 8.2940e+09 8.2907e+09 0.04% - 0s
0 0 8.2907e+09 0 1 8.2940e+09 8.2907e+09 0.04% - 0s
0 0 8.2907e+09 0 2 8.2940e+09 8.2907e+09 0.04% - 0s
0 0 8.2908e+09 0 1 8.2940e+09 8.2908e+09 0.04% - 0s
0 0 8.2908e+09 0 4 8.2940e+09 8.2908e+09 0.04% - 0s
0 0 8.2908e+09 0 4 8.2940e+09 8.2908e+09 0.04% - 0s
H 0 0 8.291465e+09 8.2908e+09 0.01% - 0s
Cutting planes:
Gomory: 2
MIR: 1
Explored 1 nodes (1031 simplex iterations) in 0.07 seconds (0.03 work units)
Thread count was 12 (of 12 available processors)
Solution count 4: 8.29147e+09 8.29398e+09 8.29827e+09 9.75713e+09
Optimal solution found (tolerance 1.00e-04)
Best objective 8.291465302389e+09, best bound 8.290781665333e+09, gap 0.0082%
</pre></div></div>
</div>
<p>In the log above, the <code class="docutils literal notranslate"><span class="pre">MIP</span> <span class="pre">start</span></code> line is missing, and Gurobi had to start with a significantly inferior initial solution. The solver was still able to find the optimal solution at the end, but it required using its own internal heuristic procedures. In this example, because we solve very small optimization problems, there was almost no difference in terms of running time, but the difference can be significant for larger problems.</p>
</div>
<div class="section" id="Accessing-the-solution">
<h2><span class="section-number">2.6. </span>Accessing the solution<a class="headerlink" href="#Accessing-the-solution" title="Permalink to this headline"></a></h2>
<p>In the example above, we used <code class="docutils literal notranslate"><span class="pre">LearningSolver.solve</span></code> together with data files to solve both the training and the test instances. The optimal solutions were saved to HDF5 files in the train/test folders, and could be retrieved by reading theses files, but that is not very convenient. In the following example, we show how to build and solve a Pyomo model entirely in-memory, using our trained solver.</p>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[12]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">data</span> <span class="o">=</span> <span class="n">random_uc_data</span><span class="p">(</span><span class="n">samples</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="o">=</span><span class="mi">500</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">build_uc_model</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">solver_ml</span><span class="o">.</span><span class="n">optimize</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;obj =&quot;</span><span class="p">,</span> <span class="n">model</span><span class="o">.</span><span class="n">inner</span><span class="o">.</span><span class="n">objVal</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;x =&quot;</span><span class="p">,</span> <span class="p">[</span><span class="n">model</span><span class="o">.</span><span class="n">inner</span><span class="o">.</span><span class="n">_x</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">x</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">)])</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;y =&quot;</span><span class="p">,</span> <span class="p">[</span><span class="n">model</span><span class="o">.</span><span class="n">inner</span><span class="o">.</span><span class="n">_y</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">x</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">)])</span>
</pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area docutils container">
<div class="highlight"><pre>
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]
Thread count: 6 physical cores, 12 logical processors, using up to 12 threads
Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros
Model fingerprint: 0x19042f12
Coefficient statistics:
Matrix range [1e+00, 2e+06]
Objective range [1e+00, 6e+07]
Bounds range [1e+00, 1e+00]
RHS range [3e+08, 3e+08]
Presolve removed 1000 rows and 500 columns
Presolve time: 0.00s
Presolved: 1 rows, 500 columns, 500 nonzeros
Iteration Objective Primal Inf. Dual Inf. Time
0 6.5917580e+09 5.627453e+04 0.000000e+00 0s
1 8.2535968e+09 0.000000e+00 0.000000e+00 0s
Solved in 1 iterations and 0.01 seconds (0.00 work units)
Optimal objective 8.253596777e+09
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]
Thread count: 6 physical cores, 12 logical processors, using up to 12 threads
Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros
Model fingerprint: 0x8ee64638
Variable types: 500 continuous, 500 integer (500 binary)
Coefficient statistics:
Matrix range [1e+00, 2e+06]
Objective range [1e+00, 6e+07]
Bounds range [1e+00, 1e+00]
RHS range [3e+08, 3e+08]
User MIP start produced solution with objective 8.25814e+09 (0.01s)
User MIP start produced solution with objective 8.25512e+09 (0.01s)
User MIP start produced solution with objective 8.25459e+09 (0.04s)
User MIP start produced solution with objective 8.25459e+09 (0.04s)
Loaded user MIP start with objective 8.25459e+09
Presolve time: 0.01s
Presolved: 1001 rows, 1000 columns, 2500 nonzeros
Variable types: 500 continuous, 500 integer (500 binary)
Root relaxation: objective 8.253597e+09, 512 iterations, 0.00 seconds (0.00 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
0 0 8.2536e+09 0 1 8.2546e+09 8.2536e+09 0.01% - 0s
0 0 8.2537e+09 0 3 8.2546e+09 8.2537e+09 0.01% - 0s
0 0 8.2537e+09 0 1 8.2546e+09 8.2537e+09 0.01% - 0s
0 0 8.2537e+09 0 4 8.2546e+09 8.2537e+09 0.01% - 0s
0 0 8.2537e+09 0 4 8.2546e+09 8.2537e+09 0.01% - 0s
0 0 8.2538e+09 0 4 8.2546e+09 8.2538e+09 0.01% - 0s
0 0 8.2538e+09 0 5 8.2546e+09 8.2538e+09 0.01% - 0s
0 0 8.2538e+09 0 6 8.2546e+09 8.2538e+09 0.01% - 0s
Cutting planes:
Cover: 1
MIR: 2
StrongCG: 1
Flow cover: 1
Explored 1 nodes (575 simplex iterations) in 0.12 seconds (0.01 work units)
Thread count was 12 (of 12 available processors)
Solution count 3: 8.25459e+09 8.25512e+09 8.25814e+09
Optimal solution found (tolerance 1.00e-04)
Best objective 8.254590409970e+09, best bound 8.253768093811e+09, gap 0.0100%
obj = 8254590409.969726
x = [1.0, 1.0, 0.0]
y = [935662.0949263407, 1604270.0218116897, 0.0]
</pre></div></div>
</div>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[ ]:
</pre></div>
</div>
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span>
</pre></div>
</div>
</div>
</div>
</div>
</div>
<div class='prev-next-bottom'>
<a class='left-prev' id="prev-link" href="../getting-started-pyomo/" title="previous page"><span class="section-number">1. </span>Getting started (Pyomo)</a>
<a class='right-next' id="next-link" href="../getting-started-jump/" title="next page"><span class="section-number">3. </span>Getting started (JuMP)</a>
</div>
</div>
</div>
<footer class="footer mt-5 mt-md-0">
<div class="container">
<p>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>
</main>
</div>
</div>
<script src="../../_static/js/index.1c5a1a01449ed65a7b51.js"></script>
</body>
</html>

@ -0,0 +1,680 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "6b8983b1",
"metadata": {
"tags": []
},
"source": [
"# Getting started (JuMP)\n",
"\n",
"## Introduction\n",
"\n",
"**MIPLearn** is an open source framework that uses machine learning (ML) to accelerate the performance of mixed-integer programming solvers (e.g. Gurobi, CPLEX, XPRESS). In this tutorial, we will:\n",
"\n",
"1. Install the Julia/JuMP version of MIPLearn\n",
"2. Model a simple optimization problem using JuMP\n",
"3. Generate training data and train the ML models\n",
"4. Use the ML models together Gurobi to solve new instances\n",
"\n",
"<div class=\"alert alert-warning\">\n",
"Warning\n",
" \n",
"MIPLearn is still in early development stage. If run into any bugs or issues, please submit a bug report in our GitHub repository. Comments, suggestions and pull requests are also very welcome!\n",
" \n",
"</div>\n"
]
},
{
"cell_type": "markdown",
"id": "02f0a927",
"metadata": {},
"source": [
"## Installation\n",
"\n",
"MIPLearn is available in two versions:\n",
"\n",
"- Python version, compatible with the Pyomo and Gurobipy modeling languages,\n",
"- Julia version, compatible with the JuMP modeling language.\n",
"\n",
"In this tutorial, we will demonstrate how to use and install the Python/Pyomo version of the package. The first step is to install Julia in your machine. See the [official Julia website for more instructions](https://julialang.org/downloads/). After Julia is installed, launch the Julia REPL, type `]` to enter package mode, then install MIPLearn:\n",
"\n",
"```\n",
"pkg> add MIPLearn@0.3\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "e8274543",
"metadata": {},
"source": [
"In addition to MIPLearn itself, we will also install:\n",
"\n",
"- the JuMP modeling language\n",
"- Gurobi, a state-of-the-art commercial MILP solver\n",
"- Distributions, to generate random data\n",
"- PyCall, to access ML model from Scikit-Learn\n",
"- Suppressor, to make the output cleaner\n",
"\n",
"```\n",
"pkg> add JuMP@1, Gurobi@1, Distributions@0.25, PyCall@1, Suppressor@0.2\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "a14e4550",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
" \n",
"Note\n",
"\n",
"- If you do not have a Gurobi license available, you can also follow the tutorial by installing an open-source solver, such as `HiGHS`, and replacing `Gurobi.Optimizer` by `HiGHS.Optimizer` in all the code examples.\n",
"- In the code above, we install specific version of all packages to ensure that this tutorial keeps running in the future, even when newer (and possibly incompatible) versions of the packages are released. This is usually a recommended practice for all Julia projects.\n",
" \n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "16b86823",
"metadata": {},
"source": [
"## Modeling a simple optimization problem\n",
"\n",
"To illustrate how can MIPLearn be used, we will model and solve a small optimization problem related to power systems optimization. The problem we discuss below is a simplification of the **unit commitment problem,** a practical optimization problem solved daily by electric grid operators around the world. \n",
"\n",
"Suppose that a utility company needs to decide which electrical generators should be online at each hour of the day, as well as how much power should each generator produce. More specifically, assume that the company owns $n$ generators, denoted by $g_1, \\ldots, g_n$. Each generator can either be online or offline. An online generator $g_i$ can produce between $p^\\text{min}_i$ to $p^\\text{max}_i$ megawatts of power, and it costs the company $c^\\text{fix}_i + c^\\text{var}_i y_i$, where $y_i$ is the amount of power produced. An offline generator produces nothing and costs nothing. The total amount of power to be produced needs to be exactly equal to the total demand $d$ (in megawatts).\n",
"\n",
"This simple problem can be modeled as a *mixed-integer linear optimization* problem as follows. For each generator $g_i$, let $x_i \\in \\{0,1\\}$ be a decision variable indicating whether $g_i$ is online, and let $y_i \\geq 0$ be a decision variable indicating how much power does $g_i$ produce. The problem is then given by:"
]
},
{
"cell_type": "markdown",
"id": "f12c3702",
"metadata": {},
"source": [
"$$\n",
"\\begin{align}\n",
"\\text{minimize } \\quad & \\sum_{i=1}^n \\left( c^\\text{fix}_i x_i + c^\\text{var}_i y_i \\right) \\\\\n",
"\\text{subject to } \\quad & y_i \\leq p^\\text{max}_i x_i & i=1,\\ldots,n \\\\\n",
"& y_i \\geq p^\\text{min}_i x_i & i=1,\\ldots,n \\\\\n",
"& \\sum_{i=1}^n y_i = d \\\\\n",
"& x_i \\in \\{0,1\\} & i=1,\\ldots,n \\\\\n",
"& y_i \\geq 0 & i=1,\\ldots,n\n",
"\\end{align}\n",
"$$"
]
},
{
"cell_type": "markdown",
"id": "be3989ed",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
"\n",
"Note\n",
"\n",
"We use a simplified version of the unit commitment problem in this tutorial just to make it easier to follow. MIPLearn can also handle realistic, large-scale versions of this problem.\n",
"\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "a5fd33f6",
"metadata": {},
"source": [
"Next, let us convert this abstract mathematical formulation into a concrete optimization model, using Julia and JuMP. We start by defining a data class `UnitCommitmentData`, which holds all the input data."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "c62ebff1-db40-45a1-9997-d121837f067b",
"metadata": {},
"outputs": [],
"source": [
"struct UnitCommitmentData\n",
" demand::Float64\n",
" pmin::Vector{Float64}\n",
" pmax::Vector{Float64}\n",
" cfix::Vector{Float64}\n",
" cvar::Vector{Float64}\n",
"end;"
]
},
{
"cell_type": "markdown",
"id": "29f55efa-0751-465a-9b0a-a821d46a3d40",
"metadata": {},
"source": [
"Next, we write a `build_uc_model` function, which converts the input data into a concrete JuMP model. The function accepts `UnitCommitmentData`, the data structure we previously defined, or the path to a JLD2 file containing this data."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "79ef7775-18ca-4dfa-b438-49860f762ad0",
"metadata": {},
"outputs": [],
"source": [
"using MIPLearn\n",
"using JuMP\n",
"using Gurobi\n",
"\n",
"function build_uc_model(data)\n",
" if data isa String\n",
" data = read_jld2(data)\n",
" end\n",
" model = Model(Gurobi.Optimizer)\n",
" G = 1:length(data.pmin)\n",
" @variable(model, x[G], Bin)\n",
" @variable(model, y[G] >= 0)\n",
" @objective(model, Min, sum(data.cfix[g] * x[g] + data.cvar[g] * y[g] for g in G))\n",
" @constraint(model, eq_max_power[g in G], y[g] <= data.pmax[g] * x[g])\n",
" @constraint(model, eq_min_power[g in G], y[g] >= data.pmin[g] * x[g])\n",
" @constraint(model, eq_demand, sum(y[g] for g in G) == data.demand)\n",
" return JumpModel(model)\n",
"end;"
]
},
{
"cell_type": "markdown",
"id": "c22714a3",
"metadata": {},
"source": [
"At this point, we can already use Gurobi to find optimal solutions to any instance of this problem. To illustrate this, let us solve a small instance with three generators:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "dd828d68-fd43-4d2a-a058-3e2628d99d9e",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:01:10.993801745Z",
"start_time": "2023-06-06T20:01:10.887580927Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 7 rows, 6 columns and 15 nonzeros\n",
"Model fingerprint: 0x55e33a07\n",
"Variable types: 3 continuous, 3 integer (3 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 7e+01]\n",
" Objective range [2e+00, 7e+02]\n",
" Bounds range [0e+00, 0e+00]\n",
" RHS range [1e+02, 1e+02]\n",
"Presolve removed 2 rows and 1 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 5 rows, 5 columns, 13 nonzeros\n",
"Variable types: 0 continuous, 5 integer (3 binary)\n",
"Found heuristic solution: objective 1400.0000000\n",
"\n",
"Root relaxation: objective 1.035000e+03, 3 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 1035.00000 0 1 1400.00000 1035.00000 26.1% - 0s\n",
" 0 0 1105.71429 0 1 1400.00000 1105.71429 21.0% - 0s\n",
"* 0 0 0 1320.0000000 1320.00000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (5 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 2: 1320 1400 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 1.320000000000e+03, best bound 1.320000000000e+03, gap 0.0000%\n",
"\n",
"User-callback calls 371, time in user-callback 0.00 sec\n",
"objective_value(model.inner) = 1320.0\n",
"Vector(value.(model.inner[:x])) = [-0.0, 1.0, 1.0]\n",
"Vector(value.(model.inner[:y])) = [0.0, 60.0, 40.0]\n"
]
}
],
"source": [
"model = build_uc_model(\n",
" UnitCommitmentData(\n",
" 100.0, # demand\n",
" [10, 20, 30], # pmin\n",
" [50, 60, 70], # pmax\n",
" [700, 600, 500], # cfix\n",
" [1.5, 2.0, 2.5], # cvar\n",
" )\n",
")\n",
"model.optimize()\n",
"@show objective_value(model.inner)\n",
"@show Vector(value.(model.inner[:x]))\n",
"@show Vector(value.(model.inner[:y]));"
]
},
{
"cell_type": "markdown",
"id": "41b03bbc",
"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."
]
},
{
"cell_type": "markdown",
"id": "01f576e1-1790-425e-9e5c-9fa07b6f4c26",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
" \n",
"Notes\n",
" \n",
"- In the example above, `JumpModel` is just a thin wrapper around a standard JuMP model. This wrapper allows MIPLearn to be solver- and modeling-language-agnostic. The wrapper provides only a few basic methods, such as `optimize`. For more control, and to query the solution, the original JuMP model can be accessed through `model.inner`, as illustrated above.\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "cf60c1dd",
"metadata": {},
"source": [
"## Generating training data\n",
"\n",
"Although Gurobi could solve the small example above in a fraction of a second, it gets slower for larger and more complex versions of the problem. If this is a problem that needs to be solved frequently, as it is often the case in practice, it could make sense to spend some time upfront generating a **trained** solver, which can optimize new instances (similar to the ones it was trained on) faster.\n",
"\n",
"In the following, we will use MIPLearn to train machine learning models that is able to predict the optimal solution for instances that follow a given probability distribution, then it will provide this predicted solution to Gurobi as a warm start. Before we can train the model, we need to collect training data by solving a large number of instances. In real-world situations, we may construct these training instances based on historical data. In this tutorial, we will construct them using a random instance generator:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "1326efd7-3869-4137-ab6b-df9cb609a7e0",
"metadata": {},
"outputs": [],
"source": [
"using Distributions\n",
"using Random\n",
"\n",
"function random_uc_data(; samples::Int, n::Int, seed::Int=42)::Vector\n",
" Random.seed!(seed)\n",
" pmin = rand(Uniform(100_000, 500_000), n)\n",
" pmax = pmin .* rand(Uniform(2, 2.5), n)\n",
" cfix = pmin .* rand(Uniform(100, 125), n)\n",
" cvar = rand(Uniform(1.25, 1.50), n)\n",
" return [\n",
" UnitCommitmentData(\n",
" sum(pmax) * rand(Uniform(0.5, 0.75)),\n",
" pmin,\n",
" pmax,\n",
" cfix,\n",
" cvar,\n",
" )\n",
" for _ in 1:samples\n",
" ]\n",
"end;"
]
},
{
"cell_type": "markdown",
"id": "3a03a7ac",
"metadata": {},
"source": [
"In this example, for simplicity, only the demands change from one instance to the next. We could also have randomized the costs, production limits or even the number of units. 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",
"\n",
"Now we generate 500 instances of this problem, each one with 50 generators, and we use 450 of these instances for training. After generating the instances, we write them to individual files. MIPLearn uses files during the training process because, for large-scale optimization problems, it is often impractical to hold in memory the entire training data, as well as the concrete Pyomo models. Files also make it much easier to solve multiple instances simultaneously, potentially on multiple machines. The code below generates the files `uc/train/00001.jld2`, `uc/train/00002.jld2`, etc., which contain the input data in JLD2 format."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "6156752c",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:03:04.782830561Z",
"start_time": "2023-06-06T20:03:04.530421396Z"
}
},
"outputs": [],
"source": [
"data = random_uc_data(samples=500, n=500)\n",
"train_data = write_jld2(data[1:450], \"uc/train\")\n",
"test_data = write_jld2(data[451:500], \"uc/test\");"
]
},
{
"cell_type": "markdown",
"id": "b17af877",
"metadata": {},
"source": [
"Finally, we use `BasicCollector` to collect the optimal solutions and other useful training data for all training instances. The data is stored in HDF5 files `uc/train/00001.h5`, `uc/train/00002.h5`, etc. The optimization models are also exported to compressed MPS files `uc/train/00001.mps.gz`, `uc/train/00002.mps.gz`, etc."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "7623f002",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:03:35.571497019Z",
"start_time": "2023-06-06T20:03:25.804104036Z"
}
},
"outputs": [],
"source": [
"using Suppressor\n",
"@suppress_out begin\n",
" bc = BasicCollector()\n",
" bc.collect(train_data, build_uc_model)\n",
"end"
]
},
{
"cell_type": "markdown",
"id": "c42b1be1-9723-4827-82d8-974afa51ef9f",
"metadata": {},
"source": [
"## Training and solving test instances"
]
},
{
"cell_type": "markdown",
"id": "a33c6aa4-f0b8-4ccb-9935-01f7d7de2a1c",
"metadata": {},
"source": [
"With training data in hand, we can now design and train a machine learning model to accelerate solver performance. In this tutorial, for illustration purposes, we will use ML to generate a good warm start using $k$-nearest neighbors. More specifically, the strategy is to:\n",
"\n",
"1. Memorize the optimal solutions of all training instances;\n",
"2. Given a test instance, find the 25 most similar training instances, based on constraint right-hand sides;\n",
"3. Merge their optimal solutions into a single partial solution; specifically, only assign values to the binary variables that agree unanimously.\n",
"4. Provide this partial solution to the solver as a warm start.\n",
"\n",
"This simple strategy can be implemented as shown below, using `MemorizingPrimalComponent`. For more advanced strategies, and for the usage of more advanced classifiers, see the user guide."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "435f7bf8-4b09-4889-b1ec-b7b56e7d8ed2",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:05:20.497772794Z",
"start_time": "2023-06-06T20:05:20.484821405Z"
}
},
"outputs": [],
"source": [
"# Load kNN classifier from Scikit-Learn\n",
"using PyCall\n",
"KNeighborsClassifier = pyimport(\"sklearn.neighbors\").KNeighborsClassifier\n",
"\n",
"# Build the MIPLearn component\n",
"comp = MemorizingPrimalComponent(\n",
" clf=KNeighborsClassifier(n_neighbors=25),\n",
" extractor=H5FieldsExtractor(\n",
" instance_fields=[\"static_constr_rhs\"],\n",
" ),\n",
" constructor=MergeTopSolutions(25, [0.0, 1.0]),\n",
" action=SetWarmStart(),\n",
");"
]
},
{
"cell_type": "markdown",
"id": "9536e7e4-0b0d-49b0-bebd-4a848f839e94",
"metadata": {},
"source": [
"Having defined the ML strategy, we next construct `LearningSolver`, train the ML component and optimize one of the test instances."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "9d13dd50-3dcf-4673-a757-6f44dcc0dedf",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:05:22.672002339Z",
"start_time": "2023-06-06T20:05:21.447466634Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0xd2378195\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 1e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [0e+00, 0e+00]\n",
" RHS range [2e+08, 2e+08]\n",
"\n",
"User MIP start produced solution with objective 1.02165e+10 (0.00s)\n",
"Loaded user MIP start with objective 1.02165e+10\n",
"\n",
"Presolve time: 0.00s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
"Root relaxation: objective 1.021568e+10, 510 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 1.0216e+10 0 1 1.0217e+10 1.0216e+10 0.01% - 0s\n",
"\n",
"Explored 1 nodes (510 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 1: 1.02165e+10 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 1.021651058978e+10, best bound 1.021567971257e+10, gap 0.0081%\n",
"\n",
"User-callback calls 169, time in user-callback 0.00 sec\n"
]
}
],
"source": [
"solver_ml = LearningSolver(components=[comp])\n",
"solver_ml.fit(train_data)\n",
"solver_ml.optimize(test_data[1], build_uc_model);"
]
},
{
"cell_type": "markdown",
"id": "61da6dad-7f56-4edb-aa26-c00eb5f946c0",
"metadata": {},
"source": [
"By examining the solve log above, specifically the line `Loaded user MIP start with objective...`, we can see that MIPLearn was able to construct an initial solution which turned out to be very close to the optimal solution to the problem. Now let us repeat the code above, but a solver which does not apply any ML strategies. Note that our previously-defined component is not provided."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "2ff391ed-e855-4228-aa09-a7641d8c2893",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:05:46.969575966Z",
"start_time": "2023-06-06T20:05:46.420803286Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0xb45c0594\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 1e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [0e+00, 0e+00]\n",
" RHS range [2e+08, 2e+08]\n",
"Presolve time: 0.00s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Found heuristic solution: objective 1.071463e+10\n",
"\n",
"Root relaxation: objective 1.021568e+10, 510 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 1.0216e+10 0 1 1.0715e+10 1.0216e+10 4.66% - 0s\n",
"H 0 0 1.025162e+10 1.0216e+10 0.35% - 0s\n",
" 0 0 1.0216e+10 0 1 1.0252e+10 1.0216e+10 0.35% - 0s\n",
"H 0 0 1.023090e+10 1.0216e+10 0.15% - 0s\n",
"H 0 0 1.022335e+10 1.0216e+10 0.07% - 0s\n",
"H 0 0 1.022281e+10 1.0216e+10 0.07% - 0s\n",
"H 0 0 1.021753e+10 1.0216e+10 0.02% - 0s\n",
"H 0 0 1.021752e+10 1.0216e+10 0.02% - 0s\n",
" 0 0 1.0216e+10 0 3 1.0218e+10 1.0216e+10 0.02% - 0s\n",
" 0 0 1.0216e+10 0 1 1.0218e+10 1.0216e+10 0.02% - 0s\n",
"H 0 0 1.021651e+10 1.0216e+10 0.01% - 0s\n",
"\n",
"Explored 1 nodes (764 simplex iterations) in 0.03 seconds (0.02 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 7: 1.02165e+10 1.02175e+10 1.02228e+10 ... 1.07146e+10\n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 1.021651058978e+10, best bound 1.021573363741e+10, gap 0.0076%\n",
"\n",
"User-callback calls 204, time in user-callback 0.00 sec\n"
]
}
],
"source": [
"solver_baseline = LearningSolver(components=[])\n",
"solver_baseline.fit(train_data)\n",
"solver_baseline.optimize(test_data[1], build_uc_model);"
]
},
{
"cell_type": "markdown",
"id": "b6d37b88-9fcc-43ee-ac1e-2a7b1e51a266",
"metadata": {},
"source": [
"In the log above, the `MIP start` line is missing, and Gurobi had to start with a significantly inferior initial solution. The solver was still able to find the optimal solution at the end, but it required using its own internal heuristic procedures. In this example, because we solve very small optimization problems, there was almost no difference in terms of running time, but the difference can be significant for larger problems."
]
},
{
"cell_type": "markdown",
"id": "eec97f06",
"metadata": {
"tags": []
},
"source": [
"## Accessing the solution\n",
"\n",
"In the example above, we used `LearningSolver.solve` together with data files to solve both the training and the test instances. The optimal solutions were saved to HDF5 files in the train/test folders, and could be retrieved by reading theses files, but that is not very convenient. In the following example, we show how to build and solve a JuMP model entirely in-memory, using our trained solver."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "67a6cd18",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:06:26.913448568Z",
"start_time": "2023-06-06T20:06:26.169047914Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x974a7fba\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 1e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [0e+00, 0e+00]\n",
" RHS range [2e+08, 2e+08]\n",
"\n",
"User MIP start produced solution with objective 9.86729e+09 (0.00s)\n",
"User MIP start produced solution with objective 9.86675e+09 (0.00s)\n",
"User MIP start produced solution with objective 9.86654e+09 (0.01s)\n",
"User MIP start produced solution with objective 9.8661e+09 (0.01s)\n",
"Loaded user MIP start with objective 9.8661e+09\n",
"\n",
"Presolve time: 0.00s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
"Root relaxation: objective 9.865344e+09, 510 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 9.8653e+09 0 1 9.8661e+09 9.8653e+09 0.01% - 0s\n",
"\n",
"Explored 1 nodes (510 simplex iterations) in 0.02 seconds (0.01 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"\n",
"Solution count 4: 9.8661e+09 9.86654e+09 9.86675e+09 9.86729e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 9.866096485614e+09, best bound 9.865343669936e+09, gap 0.0076%\n",
"\n",
"User-callback calls 182, time in user-callback 0.00 sec\n",
"objective_value(model.inner) = 9.866096485613789e9\n"
]
}
],
"source": [
"data = random_uc_data(samples=1, n=500)[1]\n",
"model = build_uc_model(data)\n",
"solver_ml.optimize(model)\n",
"@show objective_value(model.inner);"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.9.0",
"language": "julia",
"name": "julia-1.9"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.9.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

@ -0,0 +1,756 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>3. Getting started (JuMP) &#8212; MIPLearn 0.3</title>
<link href="../../_static/css/theme.css" rel="stylesheet" />
<link href="../../_static/css/index.c5995385ac14fb8791e8eb36b4908be2.css" rel="stylesheet" />
<link rel="stylesheet"
href="../../_static/vendor/fontawesome/5.13.0/css/all.min.css">
<link rel="preload" as="font" type="font/woff2" crossorigin
href="../../_static/vendor/fontawesome/5.13.0/webfonts/fa-solid-900.woff2">
<link rel="preload" as="font" type="font/woff2" crossorigin
href="../../_static/vendor/fontawesome/5.13.0/webfonts/fa-brands-400.woff2">
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../_static/sphinx-book-theme.acff12b8f9c144ce68a297486a2fa670.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css" />
<link rel="stylesheet" type="text/css" href="../../_static/custom.css" />
<link rel="preload" as="script" href="../../_static/js/index.1c5a1a01449ed65a7b51.js">
<script id="documentation_options" data-url_root="../../" src="../../_static/documentation_options.js"></script>
<script src="../../_static/jquery.js"></script>
<script src="../../_static/underscore.js"></script>
<script src="../../_static/doctools.js"></script>
<script crossorigin="anonymous" integrity="sha256-Ae2Vz/4ePdIu6ZyI/5ZGsYnb+m0JlOmKPjt6XZ9JJkA=" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"></script>
<script src="../../_static/sphinx-book-theme.12a9622fbb08dcb3a2a40b2c02b83a57.js"></script>
<script async="async" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/x-mathjax-config">MathJax.Hub.Config({"tex2jax": {"inlineMath": [["\\(", "\\)"]], "displayMath": [["\\[", "\\]"]], "processRefs": false, "processEnvironments": false}})</script>
<link rel="index" title="Index" href="../../genindex/" />
<link rel="search" title="Search" href="../../search/" />
<link rel="next" title="4. Benchmark Problems" href="../../guide/problems/" />
<link rel="prev" title="2. Getting started (Gurobipy)" href="../getting-started-gurobipy/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="docsearch:language" content="en" />
</head>
<body data-spy="scroll" data-target="#bd-toc-nav" data-offset="80">
<div class="container-fluid" id="banner"></div>
<div class="container-xl">
<div class="row">
<div class="col-12 col-md-3 bd-sidebar site-navigation show" id="site-navigation">
<div class="navbar-brand-box">
<a class="navbar-brand text-wrap" href="../../">
<h1 class="site-logo" id="site-title">MIPLearn 0.3</h1>
</a>
</div><form class="bd-search d-flex align-items-center" action="../../search/" method="get">
<i class="icon fas fa-search"></i>
<input type="search" class="form-control" name="q" id="search-input" placeholder="Search the docs ..." aria-label="Search the docs ..." autocomplete="off" >
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main navigation">
<div class="bd-toc-item active">
<p class="caption">
<span class="caption-text">
Tutorials
</span>
</p>
<ul class="current nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../getting-started-pyomo/">
1. Getting started (Pyomo)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../getting-started-gurobipy/">
2. Getting started (Gurobipy)
</a>
</li>
<li class="toctree-l1 current active">
<a class="current reference internal" href="#">
3. Getting started (JuMP)
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
User Guide
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../guide/problems/">
4. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/collectors/">
5. Training Data Collectors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/features/">
6. Feature Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/primal/">
7. Primal Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../guide/solvers/">
8. Solvers
</a>
</li>
</ul>
<p class="caption">
<span class="caption-text">
Python API Reference
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="../../api/problems/">
9. Benchmark Problems
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/collectors/">
10. Collectors &amp; Extractors
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/components/">
11. Components
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/solvers/">
12. Solvers
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="../../api/helpers/">
13. Helpers
</a>
</li>
</ul>
</div>
</nav> <!-- To handle the deprecated key -->
</div>
<main class="col py-md-3 pl-md-4 bd-content overflow-auto" role="main">
<div class="topbar container-xl fixed-top">
<div class="topbar-contents row">
<div class="col-12 col-md-3 bd-topbar-whitespace site-navigation show"></div>
<div class="col pl-md-4 topbar-main">
<button id="navbar-toggler" class="navbar-toggler ml-0" type="button" data-toggle="collapse"
data-toggle="tooltip" data-placement="bottom" data-target=".site-navigation" aria-controls="navbar-menu"
aria-expanded="true" aria-label="Toggle navigation" aria-controls="site-navigation"
title="Toggle navigation" data-toggle="tooltip" data-placement="left">
<i class="fas fa-bars"></i>
<i class="fas fa-arrow-left"></i>
<i class="fas fa-arrow-up"></i>
</button>
<div class="dropdown-buttons-trigger">
<button id="dropdown-buttons-trigger" class="btn btn-secondary topbarbtn" aria-label="Download this page"><i
class="fas fa-download"></i></button>
<div class="dropdown-buttons">
<!-- ipynb file if we had a myst markdown file -->
<!-- Download raw file -->
<a class="dropdown-buttons" href="../../_sources/tutorials/getting-started-jump.ipynb.txt"><button type="button"
class="btn btn-secondary topbarbtn" title="Download source file" data-toggle="tooltip"
data-placement="left">.ipynb</button></a>
<!-- Download PDF via print -->
<button type="button" id="download-print" class="btn btn-secondary topbarbtn" title="Print to PDF"
onClick="window.print()" data-toggle="tooltip" data-placement="left">.pdf</button>
</div>
</div>
<!-- Source interaction buttons -->
<!-- Full screen (wrap in <a> to have style consistency -->
<a class="full-screen-button"><button type="button" class="btn btn-secondary topbarbtn" data-toggle="tooltip"
data-placement="bottom" onclick="toggleFullScreen()" aria-label="Fullscreen mode"
title="Fullscreen mode"><i
class="fas fa-expand"></i></button></a>
<!-- Launch buttons -->
</div>
<!-- Table of contents -->
<div class="d-none d-md-block col-md-2 bd-toc show">
<div class="tocsection onthispage pt-5 pb-3">
<i class="fas fa-list"></i> Contents
</div>
<nav id="bd-toc-nav">
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Introduction">
3.1. Introduction
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Installation">
3.2. Installation
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Modeling-a-simple-optimization-problem">
3.3. Modeling a simple optimization problem
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Generating-training-data">
3.4. Generating training data
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Training-and-solving-test-instances">
3.5. Training and solving test instances
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#Accessing-the-solution">
3.6. Accessing the solution
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div id="main-content" class="row">
<div class="col-12 col-md-9 pl-md-3 pr-md-0">
<div>
<div class="section" id="Getting-started-(JuMP)">
<h1><span class="section-number">3. </span>Getting started (JuMP)<a class="headerlink" href="#Getting-started-(JuMP)" title="Permalink to this headline"></a></h1>
<div class="section" id="Introduction">
<h2><span class="section-number">3.1. </span>Introduction<a class="headerlink" href="#Introduction" title="Permalink to this headline"></a></h2>
<p><strong>MIPLearn</strong> is an open source framework that uses machine learning (ML) to accelerate the performance of mixed-integer programming solvers (e.g. Gurobi, CPLEX, XPRESS). In this tutorial, we will:</p>
<ol class="arabic simple">
<li><p>Install the Julia/JuMP version of MIPLearn</p></li>
<li><p>Model a simple optimization problem using JuMP</p></li>
<li><p>Generate training data and train the ML models</p></li>
<li><p>Use the ML models together Gurobi to solve new instances</p></li>
</ol>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>MIPLearn is still in early development stage. If run into any bugs or issues, please submit a bug report in our GitHub repository. Comments, suggestions and pull requests are also very welcome!</p>
</div>
</div>
<div class="section" id="Installation">
<h2><span class="section-number">3.2. </span>Installation<a class="headerlink" href="#Installation" title="Permalink to this headline"></a></h2>
<p>MIPLearn is available in two versions:</p>
<ul class="simple">
<li><p>Python version, compatible with the Pyomo and Gurobipy modeling languages,</p></li>
<li><p>Julia version, compatible with the JuMP modeling language.</p></li>
</ul>
<p>In this tutorial, we will demonstrate how to use and install the Python/Pyomo version of the package. The first step is to install Julia in your machine. See the <a class="reference external" href="https://julialang.org/downloads/">official Julia website for more instructions</a>. After Julia is installed, launch the Julia REPL, type <code class="docutils literal notranslate"><span class="pre">]</span></code> to enter package mode, then install MIPLearn:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>pkg&gt; add MIPLearn@0.3
</pre></div>
</div>
<p>In addition to MIPLearn itself, we will also install:</p>
<ul class="simple">
<li><p>the JuMP modeling language</p></li>
<li><p>Gurobi, a state-of-the-art commercial MILP solver</p></li>
<li><p>Distributions, to generate random data</p></li>
<li><p>PyCall, to access ML model from Scikit-Learn</p></li>
<li><p>Suppressor, to make the output cleaner</p></li>
</ul>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>pkg&gt; add JuMP@1, Gurobi@1, Distributions@0.25, PyCall@1, Suppressor@0.2
</pre></div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<ul class="simple">
<li><p>If you do not have a Gurobi license available, you can also follow the tutorial by installing an open-source solver, such as <code class="docutils literal notranslate"><span class="pre">HiGHS</span></code>, and replacing <code class="docutils literal notranslate"><span class="pre">Gurobi.Optimizer</span></code> by <code class="docutils literal notranslate"><span class="pre">HiGHS.Optimizer</span></code> in all the code examples.</p></li>
<li><p>In the code above, we install specific version of all packages to ensure that this tutorial keeps running in the future, even when newer (and possibly incompatible) versions of the packages are released. This is usually a recommended practice for all Julia projects.</p></li>
</ul>
</div>
</div>
<div class="section" id="Modeling-a-simple-optimization-problem">
<h2><span class="section-number">3.3. </span>Modeling a simple optimization problem<a class="headerlink" href="#Modeling-a-simple-optimization-problem" title="Permalink to this headline"></a></h2>
<p>To illustrate how can MIPLearn be used, we will model and solve a small optimization problem related to power systems optimization. The problem we discuss below is a simplification of the <strong>unit commitment problem,</strong> a practical optimization problem solved daily by electric grid operators around the world.</p>
<p>Suppose that a utility company needs to decide which electrical generators should be online at each hour of the day, as well as how much power should each generator produce. More specifically, assume that the company owns <span class="math notranslate nohighlight">\(n\)</span> generators, denoted by <span class="math notranslate nohighlight">\(g_1, \ldots, g_n\)</span>. Each generator can either be online or offline. An online generator <span class="math notranslate nohighlight">\(g_i\)</span> can produce between <span class="math notranslate nohighlight">\(p^\text{min}_i\)</span> to <span class="math notranslate nohighlight">\(p^\text{max}_i\)</span> megawatts of power, and it costs the company
<span class="math notranslate nohighlight">\(c^\text{fix}_i + c^\text{var}_i y_i\)</span>, where <span class="math notranslate nohighlight">\(y_i\)</span> is the amount of power produced. An offline generator produces nothing and costs nothing. The total amount of power to be produced needs to be exactly equal to the total demand <span class="math notranslate nohighlight">\(d\)</span> (in megawatts).</p>
<p>This simple problem can be modeled as a <em>mixed-integer linear optimization</em> problem as follows. For each generator <span class="math notranslate nohighlight">\(g_i\)</span>, let <span class="math notranslate nohighlight">\(x_i \in \{0,1\}\)</span> be a decision variable indicating whether <span class="math notranslate nohighlight">\(g_i\)</span> is online, and let <span class="math notranslate nohighlight">\(y_i \geq 0\)</span> be a decision variable indicating how much power does <span class="math notranslate nohighlight">\(g_i\)</span> produce. The problem is then given by:</p>
<div class="math notranslate nohighlight">
\[\begin{split}\begin{align}
\text{minimize } \quad &amp; \sum_{i=1}^n \left( c^\text{fix}_i x_i + c^\text{var}_i y_i \right) \\
\text{subject to } \quad &amp; y_i \leq p^\text{max}_i x_i &amp; i=1,\ldots,n \\
&amp; y_i \geq p^\text{min}_i x_i &amp; i=1,\ldots,n \\
&amp; \sum_{i=1}^n y_i = d \\
&amp; x_i \in \{0,1\} &amp; i=1,\ldots,n \\
&amp; y_i \geq 0 &amp; i=1,\ldots,n
\end{align}\end{split}\]</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>We use a simplified version of the unit commitment problem in this tutorial just to make it easier to follow. MIPLearn can also handle realistic, large-scale versions of this problem.</p>
</div>
<p>Next, let us convert this abstract mathematical formulation into a concrete optimization model, using Julia and JuMP. We start by defining a data class <code class="docutils literal notranslate"><span class="pre">UnitCommitmentData</span></code>, which holds all the input data.</p>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[1]:
</pre></div>
</div>
<div class="input_area highlight-julia notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span> <span class="kt">UnitCommitmentData</span><span class="w"></span>
<span class="w"> </span><span class="n">demand</span><span class="o">::</span><span class="kt">Float64</span><span class="w"></span>
<span class="w"> </span><span class="n">pmin</span><span class="o">::</span><span class="kt">Vector</span><span class="p">{</span><span class="kt">Float64</span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="n">pmax</span><span class="o">::</span><span class="kt">Vector</span><span class="p">{</span><span class="kt">Float64</span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="n">cfix</span><span class="o">::</span><span class="kt">Vector</span><span class="p">{</span><span class="kt">Float64</span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="n">cvar</span><span class="o">::</span><span class="kt">Vector</span><span class="p">{</span><span class="kt">Float64</span><span class="p">}</span><span class="w"></span>
<span class="k">end</span><span class="p">;</span><span class="w"></span>
</pre></div>
</div>
</div>
<p>Next, we write a <code class="docutils literal notranslate"><span class="pre">build_uc_model</span></code> function, which converts the input data into a concrete JuMP model. The function accepts <code class="docutils literal notranslate"><span class="pre">UnitCommitmentData</span></code>, the data structure we previously defined, or the path to a JLD2 file containing this data.</p>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[2]:
</pre></div>
</div>
<div class="input_area highlight-julia notranslate"><div class="highlight"><pre><span></span><span class="k">using</span><span class="w"> </span><span class="n">MIPLearn</span><span class="w"></span>
<span class="k">using</span><span class="w"> </span><span class="n">JuMP</span><span class="w"></span>
<span class="k">using</span><span class="w"> </span><span class="n">Gurobi</span><span class="w"></span>
<span class="k">function</span><span class="w"> </span><span class="n">build_uc_model</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="k">isa</span><span class="w"> </span><span class="kt">String</span><span class="w"></span>
<span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">read_jld2</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">end</span><span class="w"></span>
<span class="w"> </span><span class="n">model</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Model</span><span class="p">(</span><span class="n">Gurobi</span><span class="o">.</span><span class="n">Optimizer</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">G</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="o">:</span><span class="n">length</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">pmin</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nd">@variable</span><span class="p">(</span><span class="n">model</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">[</span><span class="n">G</span><span class="p">],</span><span class="w"> </span><span class="n">Bin</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nd">@variable</span><span class="p">(</span><span class="n">model</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">[</span><span class="n">G</span><span class="p">]</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nd">@objective</span><span class="p">(</span><span class="n">model</span><span class="p">,</span><span class="w"> </span><span class="n">Min</span><span class="p">,</span><span class="w"> </span><span class="n">sum</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">cfix</span><span class="p">[</span><span class="n">g</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">x</span><span class="p">[</span><span class="n">g</span><span class="p">]</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">data</span><span class="o">.</span><span class="n">cvar</span><span class="p">[</span><span class="n">g</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">y</span><span class="p">[</span><span class="n">g</span><span class="p">]</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">g</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">G</span><span class="p">))</span><span class="w"></span>
<span class="w"> </span><span class="nd">@constraint</span><span class="p">(</span><span class="n">model</span><span class="p">,</span><span class="w"> </span><span class="n">eq_max_power</span><span class="p">[</span><span class="n">g</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">G</span><span class="p">],</span><span class="w"> </span><span class="n">y</span><span class="p">[</span><span class="n">g</span><span class="p">]</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="n">data</span><span class="o">.</span><span class="n">pmax</span><span class="p">[</span><span class="n">g</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">x</span><span class="p">[</span><span class="n">g</span><span class="p">])</span><span class="w"></span>
<span class="w"> </span><span class="nd">@constraint</span><span class="p">(</span><span class="n">model</span><span class="p">,</span><span class="w"> </span><span class="n">eq_min_power</span><span class="p">[</span><span class="n">g</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">G</span><span class="p">],</span><span class="w"> </span><span class="n">y</span><span class="p">[</span><span class="n">g</span><span class="p">]</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="n">data</span><span class="o">.</span><span class="n">pmin</span><span class="p">[</span><span class="n">g</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">x</span><span class="p">[</span><span class="n">g</span><span class="p">])</span><span class="w"></span>
<span class="w"> </span><span class="nd">@constraint</span><span class="p">(</span><span class="n">model</span><span class="p">,</span><span class="w"> </span><span class="n">eq_demand</span><span class="p">,</span><span class="w"> </span><span class="n">sum</span><span class="p">(</span><span class="n">y</span><span class="p">[</span><span class="n">g</span><span class="p">]</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">g</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">G</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">data</span><span class="o">.</span><span class="n">demand</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">JumpModel</span><span class="p">(</span><span class="n">model</span><span class="p">)</span><span class="w"></span>
<span class="k">end</span><span class="p">;</span><span class="w"></span>
</pre></div>
</div>
</div>
<p>At this point, we can already use Gurobi to find optimal solutions to any instance of this problem. To illustrate this, let us solve a small instance with three generators:</p>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[3]:
</pre></div>
</div>
<div class="input_area highlight-julia notranslate"><div class="highlight"><pre><span></span><span class="n">model</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">build_uc_model</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="n">UnitCommitmentData</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="mf">100.0</span><span class="p">,</span><span class="w"> </span><span class="c"># demand</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="mi">20</span><span class="p">,</span><span class="w"> </span><span class="mi">30</span><span class="p">],</span><span class="w"> </span><span class="c"># pmin</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mi">50</span><span class="p">,</span><span class="w"> </span><span class="mi">60</span><span class="p">,</span><span class="w"> </span><span class="mi">70</span><span class="p">],</span><span class="w"> </span><span class="c"># pmax</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mi">700</span><span class="p">,</span><span class="w"> </span><span class="mi">600</span><span class="p">,</span><span class="w"> </span><span class="mi">500</span><span class="p">],</span><span class="w"> </span><span class="c"># cfix</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mf">1.5</span><span class="p">,</span><span class="w"> </span><span class="mf">2.0</span><span class="p">,</span><span class="w"> </span><span class="mf">2.5</span><span class="p">],</span><span class="w"> </span><span class="c"># cvar</span><span class="w"></span>
<span class="w"> </span><span class="p">)</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>
<span class="n">model</span><span class="o">.</span><span class="n">optimize</span><span class="p">()</span><span class="w"></span>
<span class="nd">@show</span><span class="w"> </span><span class="n">objective_value</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">inner</span><span class="p">)</span><span class="w"></span>
<span class="nd">@show</span><span class="w"> </span><span class="kt">Vector</span><span class="p">(</span><span class="n">value</span><span class="o">.</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">inner</span><span class="p">[</span><span class="ss">:x</span><span class="p">]))</span><span class="w"></span>
<span class="nd">@show</span><span class="w"> </span><span class="kt">Vector</span><span class="p">(</span><span class="n">value</span><span class="o">.</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">inner</span><span class="p">[</span><span class="ss">:y</span><span class="p">]));</span><span class="w"></span>
</pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area docutils container">
<div class="highlight"><pre>
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 16 physical cores, 32 logical processors, using up to 32 threads
Optimize a model with 7 rows, 6 columns and 15 nonzeros
Model fingerprint: 0x55e33a07
Variable types: 3 continuous, 3 integer (3 binary)
Coefficient statistics:
Matrix range [1e+00, 7e+01]
Objective range [2e+00, 7e+02]
Bounds range [0e+00, 0e+00]
RHS range [1e+02, 1e+02]
Presolve removed 2 rows and 1 columns
Presolve time: 0.00s
Presolved: 5 rows, 5 columns, 13 nonzeros
Variable types: 0 continuous, 5 integer (3 binary)
Found heuristic solution: objective 1400.0000000
Root relaxation: objective 1.035000e+03, 3 iterations, 0.00 seconds (0.00 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
0 0 1035.00000 0 1 1400.00000 1035.00000 26.1% - 0s
0 0 1105.71429 0 1 1400.00000 1105.71429 21.0% - 0s
* 0 0 0 1320.0000000 1320.00000 0.00% - 0s
Explored 1 nodes (5 simplex iterations) in 0.00 seconds (0.00 work units)
Thread count was 32 (of 32 available processors)
Solution count 2: 1320 1400
Optimal solution found (tolerance 1.00e-04)
Best objective 1.320000000000e+03, best bound 1.320000000000e+03, gap 0.0000%
User-callback calls 371, time in user-callback 0.00 sec
objective_value(model.inner) = 1320.0
Vector(value.(model.inner[:x])) = [-0.0, 1.0, 1.0]
Vector(value.(model.inner[:y])) = [0.0, 60.0, 40.0]
</pre></div></div>
</div>
<p>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.</p>
<div class="admonition note">
<p class="admonition-title">Notes</p>
<ul class="simple">
<li><p>In the example above, <code class="docutils literal notranslate"><span class="pre">JumpModel</span></code> is just a thin wrapper around a standard JuMP model. This wrapper allows MIPLearn to be solver- and modeling-language-agnostic. The wrapper provides only a few basic methods, such as <code class="docutils literal notranslate"><span class="pre">optimize</span></code>. For more control, and to query the solution, the original JuMP model can be accessed through <code class="docutils literal notranslate"><span class="pre">model.inner</span></code>, as illustrated above.</p></li>
</ul>
</div>
</div>
<div class="section" id="Generating-training-data">
<h2><span class="section-number">3.4. </span>Generating training data<a class="headerlink" href="#Generating-training-data" title="Permalink to this headline"></a></h2>
<p>Although Gurobi could solve the small example above in a fraction of a second, it gets slower for larger and more complex versions of the problem. If this is a problem that needs to be solved frequently, as it is often the case in practice, it could make sense to spend some time upfront generating a <strong>trained</strong> solver, which can optimize new instances (similar to the ones it was trained on) faster.</p>
<p>In the following, we will use MIPLearn to train machine learning models that is able to predict the optimal solution for instances that follow a given probability distribution, then it will provide this predicted solution to Gurobi as a warm start. Before we can train the model, we need to collect training data by solving a large number of instances. In real-world situations, we may construct these training instances based on historical data. In this tutorial, we will construct them using a
random instance generator:</p>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[4]:
</pre></div>
</div>
<div class="input_area highlight-julia notranslate"><div class="highlight"><pre><span></span><span class="k">using</span><span class="w"> </span><span class="n">Distributions</span><span class="w"></span>
<span class="k">using</span><span class="w"> </span><span class="n">Random</span><span class="w"></span>
<span class="k">function</span><span class="w"> </span><span class="n">random_uc_data</span><span class="p">(;</span><span class="w"> </span><span class="n">samples</span><span class="o">::</span><span class="kt">Int</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="o">::</span><span class="kt">Int</span><span class="p">,</span><span class="w"> </span><span class="n">seed</span><span class="o">::</span><span class="kt">Int</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span><span class="o">::</span><span class="kt">Vector</span><span class="w"></span>
<span class="w"> </span><span class="n">Random</span><span class="o">.</span><span class="n">seed!</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">pmin</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">rand</span><span class="p">(</span><span class="n">Uniform</span><span class="p">(</span><span class="mi">100_000</span><span class="p">,</span><span class="w"> </span><span class="mi">500_000</span><span class="p">),</span><span class="w"> </span><span class="n">n</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">pmax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pmin</span><span class="w"> </span><span class="o">.*</span><span class="w"> </span><span class="n">rand</span><span class="p">(</span><span class="n">Uniform</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mf">2.5</span><span class="p">),</span><span class="w"> </span><span class="n">n</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">cfix</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pmin</span><span class="w"> </span><span class="o">.*</span><span class="w"> </span><span class="n">rand</span><span class="p">(</span><span class="n">Uniform</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span><span class="w"> </span><span class="mi">125</span><span class="p">),</span><span class="w"> </span><span class="n">n</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">cvar</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">rand</span><span class="p">(</span><span class="n">Uniform</span><span class="p">(</span><span class="mf">1.25</span><span class="p">,</span><span class="w"> </span><span class="mf">1.50</span><span class="p">),</span><span class="w"> </span><span class="n">n</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">[</span><span class="w"></span>
<span class="w"> </span><span class="n">UnitCommitmentData</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="n">sum</span><span class="p">(</span><span class="n">pmax</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">rand</span><span class="p">(</span><span class="n">Uniform</span><span class="p">(</span><span class="mf">0.5</span><span class="p">,</span><span class="w"> </span><span class="mf">0.75</span><span class="p">)),</span><span class="w"></span>
<span class="w"> </span><span class="n">pmin</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">pmax</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">cfix</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">cvar</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">1</span><span class="o">:</span><span class="n">samples</span><span class="w"></span>
<span class="w"> </span><span class="p">]</span><span class="w"></span>
<span class="k">end</span><span class="p">;</span><span class="w"></span>
</pre></div>
</div>
</div>
<p>In this example, for simplicity, only the demands change from one instance to the next. We could also have randomized the costs, production limits or even the number of units. The more randomization we have in the training data, however, the more challenging it is for the machine learning models to learn solution patterns.</p>
<p>Now we generate 500 instances of this problem, each one with 50 generators, and we use 450 of these instances for training. After generating the instances, we write them to individual files. MIPLearn uses files during the training process because, for large-scale optimization problems, it is often impractical to hold in memory the entire training data, as well as the concrete Pyomo models. Files also make it much easier to solve multiple instances simultaneously, potentially on multiple
machines. The code below generates the files <code class="docutils literal notranslate"><span class="pre">uc/train/00001.jld2</span></code>, <code class="docutils literal notranslate"><span class="pre">uc/train/00002.jld2</span></code>, etc., which contain the input data in JLD2 format.</p>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[5]:
</pre></div>
</div>
<div class="input_area highlight-julia notranslate"><div class="highlight"><pre><span></span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">random_uc_data</span><span class="p">(</span><span class="n">samples</span><span class="o">=</span><span class="mi">500</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="o">=</span><span class="mi">500</span><span class="p">)</span><span class="w"></span>
<span class="n">train_data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">write_jld2</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="o">:</span><span class="mi">450</span><span class="p">],</span><span class="w"> </span><span class="s">&quot;uc/train&quot;</span><span class="p">)</span><span class="w"></span>
<span class="n">test_data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">write_jld2</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="mi">451</span><span class="o">:</span><span class="mi">500</span><span class="p">],</span><span class="w"> </span><span class="s">&quot;uc/test&quot;</span><span class="p">);</span><span class="w"></span>
</pre></div>
</div>
</div>
<p>Finally, we use <code class="docutils literal notranslate"><span class="pre">BasicCollector</span></code> to collect the optimal solutions and other useful training data for all training instances. The data is stored in HDF5 files <code class="docutils literal notranslate"><span class="pre">uc/train/00001.h5</span></code>, <code class="docutils literal notranslate"><span class="pre">uc/train/00002.h5</span></code>, etc. The optimization models are also exported to compressed MPS files <code class="docutils literal notranslate"><span class="pre">uc/train/00001.mps.gz</span></code>, <code class="docutils literal notranslate"><span class="pre">uc/train/00002.mps.gz</span></code>, etc.</p>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[6]:
</pre></div>
</div>
<div class="input_area highlight-julia notranslate"><div class="highlight"><pre><span></span><span class="k">using</span><span class="w"> </span><span class="n">Suppressor</span><span class="w"></span>
<span class="nd">@suppress_out</span><span class="w"> </span><span class="k">begin</span><span class="w"></span>
<span class="w"> </span><span class="n">bc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BasicCollector</span><span class="p">()</span><span class="w"></span>
<span class="w"> </span><span class="n">bc</span><span class="o">.</span><span class="n">collect</span><span class="p">(</span><span class="n">train_data</span><span class="p">,</span><span class="w"> </span><span class="n">build_uc_model</span><span class="p">)</span><span class="w"></span>
<span class="k">end</span><span class="w"></span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="Training-and-solving-test-instances">
<h2><span class="section-number">3.5. </span>Training and solving test instances<a class="headerlink" href="#Training-and-solving-test-instances" title="Permalink to this headline"></a></h2>
<p>With training data in hand, we can now design and train a machine learning model to accelerate solver performance. In this tutorial, for illustration purposes, we will use ML to generate a good warm start using <span class="math notranslate nohighlight">\(k\)</span>-nearest neighbors. More specifically, the strategy is to:</p>
<ol class="arabic simple">
<li><p>Memorize the optimal solutions of all training instances;</p></li>
<li><p>Given a test instance, find the 25 most similar training instances, based on constraint right-hand sides;</p></li>
<li><p>Merge their optimal solutions into a single partial solution; specifically, only assign values to the binary variables that agree unanimously.</p></li>
<li><p>Provide this partial solution to the solver as a warm start.</p></li>
</ol>
<p>This simple strategy can be implemented as shown below, using <code class="docutils literal notranslate"><span class="pre">MemorizingPrimalComponent</span></code>. For more advanced strategies, and for the usage of more advanced classifiers, see the user guide.</p>
<div class="nbinput nblast docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[7]:
</pre></div>
</div>
<div class="input_area highlight-julia notranslate"><div class="highlight"><pre><span></span><span class="c"># Load kNN classifier from Scikit-Learn</span><span class="w"></span>
<span class="k">using</span><span class="w"> </span><span class="n">PyCall</span><span class="w"></span>
<span class="n">KNeighborsClassifier</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pyimport</span><span class="p">(</span><span class="s">&quot;sklearn.neighbors&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">KNeighborsClassifier</span><span class="w"></span>
<span class="c"># Build the MIPLearn component</span><span class="w"></span>
<span class="n">comp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MemorizingPrimalComponent</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="n">clf</span><span class="o">=</span><span class="n">KNeighborsClassifier</span><span class="p">(</span><span class="n">n_neighbors</span><span class="o">=</span><span class="mi">25</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="n">extractor</span><span class="o">=</span><span class="n">H5FieldsExtractor</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="n">instance_fields</span><span class="o">=</span><span class="p">[</span><span class="s">&quot;static_constr_rhs&quot;</span><span class="p">],</span><span class="w"></span>
<span class="w"> </span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="n">constructor</span><span class="o">=</span><span class="n">MergeTopSolutions</span><span class="p">(</span><span class="mi">25</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="mf">0.0</span><span class="p">,</span><span class="w"> </span><span class="mf">1.0</span><span class="p">]),</span><span class="w"></span>
<span class="w"> </span><span class="n">action</span><span class="o">=</span><span class="n">SetWarmStart</span><span class="p">(),</span><span class="w"></span>
<span class="p">);</span><span class="w"></span>
</pre></div>
</div>
</div>
<p>Having defined the ML strategy, we next construct <code class="docutils literal notranslate"><span class="pre">LearningSolver</span></code>, train the ML component and optimize one of the test instances.</p>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[8]:
</pre></div>
</div>
<div class="input_area highlight-julia notranslate"><div class="highlight"><pre><span></span><span class="n">solver_ml</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">LearningSolver</span><span class="p">(</span><span class="n">components</span><span class="o">=</span><span class="p">[</span><span class="n">comp</span><span class="p">])</span><span class="w"></span>
<span class="n">solver_ml</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">train_data</span><span class="p">)</span><span class="w"></span>
<span class="n">solver_ml</span><span class="o">.</span><span class="n">optimize</span><span class="p">(</span><span class="n">test_data</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span><span class="w"> </span><span class="n">build_uc_model</span><span class="p">);</span><span class="w"></span>
</pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area docutils container">
<div class="highlight"><pre>
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 16 physical cores, 32 logical processors, using up to 32 threads
Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros
Model fingerprint: 0xd2378195
Variable types: 500 continuous, 500 integer (500 binary)
Coefficient statistics:
Matrix range [1e+00, 1e+06]
Objective range [1e+00, 6e+07]
Bounds range [0e+00, 0e+00]
RHS range [2e+08, 2e+08]
User MIP start produced solution with objective 1.02165e+10 (0.00s)
Loaded user MIP start with objective 1.02165e+10
Presolve time: 0.00s
Presolved: 1001 rows, 1000 columns, 2500 nonzeros
Variable types: 500 continuous, 500 integer (500 binary)
Root relaxation: objective 1.021568e+10, 510 iterations, 0.00 seconds (0.00 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
0 0 1.0216e+10 0 1 1.0217e+10 1.0216e+10 0.01% - 0s
Explored 1 nodes (510 simplex iterations) in 0.01 seconds (0.00 work units)
Thread count was 32 (of 32 available processors)
Solution count 1: 1.02165e+10
Optimal solution found (tolerance 1.00e-04)
Best objective 1.021651058978e+10, best bound 1.021567971257e+10, gap 0.0081%
User-callback calls 169, time in user-callback 0.00 sec
</pre></div></div>
</div>
<p>By examining the solve log above, specifically the line <code class="docutils literal notranslate"><span class="pre">Loaded</span> <span class="pre">user</span> <span class="pre">MIP</span> <span class="pre">start</span> <span class="pre">with</span> <span class="pre">objective...</span></code>, we can see that MIPLearn was able to construct an initial solution which turned out to be very close to the optimal solution to the problem. Now let us repeat the code above, but a solver which does not apply any ML strategies. Note that our previously-defined component is not provided.</p>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[9]:
</pre></div>
</div>
<div class="input_area highlight-julia notranslate"><div class="highlight"><pre><span></span><span class="n">solver_baseline</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">LearningSolver</span><span class="p">(</span><span class="n">components</span><span class="o">=</span><span class="p">[])</span><span class="w"></span>
<span class="n">solver_baseline</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">train_data</span><span class="p">)</span><span class="w"></span>
<span class="n">solver_baseline</span><span class="o">.</span><span class="n">optimize</span><span class="p">(</span><span class="n">test_data</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span><span class="w"> </span><span class="n">build_uc_model</span><span class="p">);</span><span class="w"></span>
</pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area docutils container">
<div class="highlight"><pre>
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 16 physical cores, 32 logical processors, using up to 32 threads
Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros
Model fingerprint: 0xb45c0594
Variable types: 500 continuous, 500 integer (500 binary)
Coefficient statistics:
Matrix range [1e+00, 1e+06]
Objective range [1e+00, 6e+07]
Bounds range [0e+00, 0e+00]
RHS range [2e+08, 2e+08]
Presolve time: 0.00s
Presolved: 1001 rows, 1000 columns, 2500 nonzeros
Variable types: 500 continuous, 500 integer (500 binary)
Found heuristic solution: objective 1.071463e+10
Root relaxation: objective 1.021568e+10, 510 iterations, 0.00 seconds (0.00 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
0 0 1.0216e+10 0 1 1.0715e+10 1.0216e+10 4.66% - 0s
H 0 0 1.025162e+10 1.0216e+10 0.35% - 0s
0 0 1.0216e+10 0 1 1.0252e+10 1.0216e+10 0.35% - 0s
H 0 0 1.023090e+10 1.0216e+10 0.15% - 0s
H 0 0 1.022335e+10 1.0216e+10 0.07% - 0s
H 0 0 1.022281e+10 1.0216e+10 0.07% - 0s
H 0 0 1.021753e+10 1.0216e+10 0.02% - 0s
H 0 0 1.021752e+10 1.0216e+10 0.02% - 0s
0 0 1.0216e+10 0 3 1.0218e+10 1.0216e+10 0.02% - 0s
0 0 1.0216e+10 0 1 1.0218e+10 1.0216e+10 0.02% - 0s
H 0 0 1.021651e+10 1.0216e+10 0.01% - 0s
Explored 1 nodes (764 simplex iterations) in 0.03 seconds (0.02 work units)
Thread count was 32 (of 32 available processors)
Solution count 7: 1.02165e+10 1.02175e+10 1.02228e+10 ... 1.07146e+10
Optimal solution found (tolerance 1.00e-04)
Best objective 1.021651058978e+10, best bound 1.021573363741e+10, gap 0.0076%
User-callback calls 204, time in user-callback 0.00 sec
</pre></div></div>
</div>
<p>In the log above, the <code class="docutils literal notranslate"><span class="pre">MIP</span> <span class="pre">start</span></code> line is missing, and Gurobi had to start with a significantly inferior initial solution. The solver was still able to find the optimal solution at the end, but it required using its own internal heuristic procedures. In this example, because we solve very small optimization problems, there was almost no difference in terms of running time, but the difference can be significant for larger problems.</p>
</div>
<div class="section" id="Accessing-the-solution">
<h2><span class="section-number">3.6. </span>Accessing the solution<a class="headerlink" href="#Accessing-the-solution" title="Permalink to this headline"></a></h2>
<p>In the example above, we used <code class="docutils literal notranslate"><span class="pre">LearningSolver.solve</span></code> together with data files to solve both the training and the test instances. The optimal solutions were saved to HDF5 files in the train/test folders, and could be retrieved by reading theses files, but that is not very convenient. In the following example, we show how to build and solve a JuMP model entirely in-memory, using our trained solver.</p>
<div class="nbinput docutils container">
<div class="prompt highlight-none notranslate"><div class="highlight"><pre><span></span>[10]:
</pre></div>
</div>
<div class="input_area highlight-julia notranslate"><div class="highlight"><pre><span></span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">random_uc_data</span><span class="p">(</span><span class="n">samples</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="o">=</span><span class="mi">500</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="w"></span>
<span class="n">model</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">build_uc_model</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="w"></span>
<span class="n">solver_ml</span><span class="o">.</span><span class="n">optimize</span><span class="p">(</span><span class="n">model</span><span class="p">)</span><span class="w"></span>
<span class="nd">@show</span><span class="w"> </span><span class="n">objective_value</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">inner</span><span class="p">);</span><span class="w"></span>
</pre></div>
</div>
</div>
<div class="nboutput nblast docutils container">
<div class="prompt empty docutils container">
</div>
<div class="output_area docutils container">
<div class="highlight"><pre>
Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)
CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 16 physical cores, 32 logical processors, using up to 32 threads
Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros
Model fingerprint: 0x974a7fba
Variable types: 500 continuous, 500 integer (500 binary)
Coefficient statistics:
Matrix range [1e+00, 1e+06]
Objective range [1e+00, 6e+07]
Bounds range [0e+00, 0e+00]
RHS range [2e+08, 2e+08]
User MIP start produced solution with objective 9.86729e+09 (0.00s)
User MIP start produced solution with objective 9.86675e+09 (0.00s)
User MIP start produced solution with objective 9.86654e+09 (0.01s)
User MIP start produced solution with objective 9.8661e+09 (0.01s)
Loaded user MIP start with objective 9.8661e+09
Presolve time: 0.00s
Presolved: 1001 rows, 1000 columns, 2500 nonzeros
Variable types: 500 continuous, 500 integer (500 binary)
Root relaxation: objective 9.865344e+09, 510 iterations, 0.00 seconds (0.00 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
0 0 9.8653e+09 0 1 9.8661e+09 9.8653e+09 0.01% - 0s
Explored 1 nodes (510 simplex iterations) in 0.02 seconds (0.01 work units)
Thread count was 32 (of 32 available processors)
Solution count 4: 9.8661e+09 9.86654e+09 9.86675e+09 9.86729e+09
Optimal solution found (tolerance 1.00e-04)
Best objective 9.866096485614e+09, best bound 9.865343669936e+09, gap 0.0076%
User-callback calls 182, time in user-callback 0.00 sec
objective_value(model.inner) = 9.866096485613789e9
</pre></div></div>
</div>
</div>
</div>
</div>
<div class='prev-next-bottom'>
<a class='left-prev' id="prev-link" href="../getting-started-gurobipy/" title="previous page"><span class="section-number">2. </span>Getting started (Gurobipy)</a>
<a class='right-next' id="next-link" href="../../guide/problems/" title="next page"><span class="section-number">4. </span>Benchmark Problems</a>
</div>
</div>
</div>
<footer class="footer mt-5 mt-md-0">
<div class="container">
<p>
&copy; Copyright 2020-2023, UChicago Argonne, LLC.<br/>
</p>
</div>
</footer>
</main>
</div>
</div>
<script src="../../_static/js/index.1c5a1a01449ed65a7b51.js"></script>
</body>
</html>

@ -11,17 +11,17 @@
"\n",
"## Introduction\n",
"\n",
"**MIPLearn** is an open source framework that uses machine learning (ML) to accelerate the performance of both commercial and open source mixed-integer programming solvers (e.g. Gurobi, CPLEX, XPRESS, Cbc or SCIP). In this tutorial, we will:\n",
"**MIPLearn** is an open source framework that uses machine learning (ML) to accelerate the performance of mixed-integer programming solvers (e.g. Gurobi, CPLEX, XPRESS). In this tutorial, we will:\n",
"\n",
"1. Install the Python/Pyomo version of MIPLearn\n",
"2. Model a simple optimization problem using JuMP\n",
"2. Model a simple optimization problem using Pyomo\n",
"3. Generate training data and train the ML models\n",
"4. Use the ML models together Gurobi to solve new instances\n",
"\n",
"<div class=\"alert alert-info\">\n",
"Note\n",
" \n",
"The Python/Pyomo version of MIPLearn is currently only compatible with with Gurobi, CPLEX and XPRESS. For broader solver compatibility, see the Julia/JuMP version of the package.\n",
"The Python/Pyomo version of MIPLearn is currently only compatible with Pyomo persistent solvers (Gurobi, CPLEX and XPRESS). For broader solver compatibility, see the Julia/JuMP version of the package.\n",
"</div>\n",
"\n",
"<div class=\"alert alert-warning\">\n",
@ -41,7 +41,7 @@
"\n",
"MIPLearn is available in two versions:\n",
"\n",
"- Python version, compatible with the Pyomo modeling language,\n",
"- Python version, compatible with the Pyomo and Gurobipy modeling languages,\n",
"- Julia version, compatible with the JuMP modeling language.\n",
"\n",
"In this tutorial, we will demonstrate how to use and install the Python/Pyomo version of the package. The first step is to install Python 3.8+ in your computer. See the [official Python website for more instructions](https://www.python.org/downloads/). After Python is installed, we proceed to install MIPLearn using `pip`:"
@ -51,10 +51,15 @@
"cell_type": "code",
"execution_count": 1,
"id": "cd8a69c1",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T19:57:33.202580815Z",
"start_time": "2023-06-06T19:57:33.198341886Z"
}
},
"outputs": [],
"source": [
"# !pip install MIPLearn==0.2.0.dev13"
"# !pip install MIPLearn==0.3.0"
]
},
{
@ -62,26 +67,30 @@
"id": "e8274543",
"metadata": {},
"source": [
"In addition to MIPLearn itself, we will also install Gurobi 9.5, a state-of-the-art commercial MILP solver. This step also install a demo license for Gurobi, which should able to solve the small optimization problems in this tutorial. A paid license is required for solving large-scale problems."
"In addition to MIPLearn itself, we will also install Gurobi 10.0, a state-of-the-art commercial MILP solver. This step also install a demo license for Gurobi, which should able to solve the small optimization problems in this tutorial. A license is required for solving larger-scale problems."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "dcc8756c",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T19:57:35.756831801Z",
"start_time": "2023-06-06T19:57:33.201767088Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Looking in indexes: https://pypi.gurobi.com\n",
"Requirement already satisfied: gurobipy<9.6,>=9.5 in /opt/anaconda3/envs/miplearn/lib/python3.8/site-packages (9.5.1)\n"
"Requirement already satisfied: gurobipy<10.1,>=10 in /home/axavier/Software/anaconda3/envs/miplearn/lib/python3.8/site-packages (10.0.1)\n"
]
}
],
"source": [
"!pip install --upgrade -i https://pypi.gurobi.com 'gurobipy>=9.5,<9.6'"
"!pip install 'gurobipy>=10,<10.1'"
]
},
{
@ -107,10 +116,16 @@
"\n",
"To illustrate how can MIPLearn be used, we will model and solve a small optimization problem related to power systems optimization. The problem we discuss below is a simplification of the **unit commitment problem,** a practical optimization problem solved daily by electric grid operators around the world. \n",
"\n",
"Suppose that you work at a utility company, and that it is your job to decide which electrical generators should be online at a certain hour of the day, as well as how much power should each generator produce. More specifically, assume that your company owns $n$ generators, denoted by $g_1, \\ldots, g_n$. Each generator can either be online or offline. An online generator $g_i$ can produce between $p^\\text{min}_i$ to $p^\\text{max}_i$ megawatts of power, and it costs your company $c^\\text{fix}_i + c^\\text{var}_i y_i$, where $y_i$ is the amount of power produced. An offline generator produces nothing and costs nothing. You also know that the total amount of power to be produced needs to be exactly equal to the total demand $d$ (in megawatts). To minimize the costs to your company, which generators should be online, and how much power should they produce?\n",
"\n",
"This simple problem can be modeled as a *mixed-integer linear optimization* problem as follows. For each generator $g_i$, let $x_i \\in \\{0,1\\}$ be a decision variable indicating whether $g_i$ is online, and let $y_i \\geq 0$ be a decision variable indicating how much power does $g_i$ produce. The problem is then given by:\n",
"Suppose that a utility company needs to decide which electrical generators should be online at each hour of the day, as well as how much power should each generator produce. More specifically, assume that the company owns $n$ generators, denoted by $g_1, \\ldots, g_n$. Each generator can either be online or offline. An online generator $g_i$ can produce between $p^\\text{min}_i$ to $p^\\text{max}_i$ megawatts of power, and it costs the company $c^\\text{fix}_i + c^\\text{var}_i y_i$, where $y_i$ is the amount of power produced. An offline generator produces nothing and costs nothing. The total amount of power to be produced needs to be exactly equal to the total demand $d$ (in megawatts).\n",
"\n",
"This simple problem can be modeled as a *mixed-integer linear optimization* problem as follows. For each generator $g_i$, let $x_i \\in \\{0,1\\}$ be a decision variable indicating whether $g_i$ is online, and let $y_i \\geq 0$ be a decision variable indicating how much power does $g_i$ produce. The problem is then given by:"
]
},
{
"cell_type": "markdown",
"id": "f12c3702",
"metadata": {},
"source": [
"$$\n",
"\\begin{align}\n",
"\\text{minimize } \\quad & \\sum_{i=1}^n \\left( c^\\text{fix}_i x_i + c^\\text{var}_i y_i \\right) \\\\\n",
@ -120,16 +135,28 @@
"& x_i \\in \\{0,1\\} & i=1,\\ldots,n \\\\\n",
"& y_i \\geq 0 & i=1,\\ldots,n\n",
"\\end{align}\n",
"$$\n",
"\n",
"$$"
]
},
{
"cell_type": "markdown",
"id": "be3989ed",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
" \n",
"\n",
"Note\n",
" \n",
"We use a simplified version of the unit commitment problem in this tutorial just to make it easier to follow. MIPLearn can also handle realistic, large-scale versions of this problem. See benchmarks for more details.\n",
" \n",
"</div>\n",
"\n",
"We use a simplified version of the unit commitment problem in this tutorial just to make it easier to follow. MIPLearn can also handle realistic, large-scale versions of this problem.\n",
"\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "a5fd33f6",
"metadata": {},
"source": [
"Next, let us convert this abstract mathematical formulation into a concrete optimization model, using Python and Pyomo. We start by defining a data class `UnitCommitmentData`, which holds all the input data."
]
},
@ -138,20 +165,27 @@
"execution_count": 3,
"id": "22a67170-10b4-43d3-8708-014d91141e73",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:00:03.278853343Z",
"start_time": "2023-06-06T20:00:03.123324067Z"
},
"tags": []
},
"outputs": [],
"source": [
"from dataclasses import dataclass\n",
"from typing import List\n",
"\n",
"import numpy as np\n",
"\n",
"\n",
"@dataclass\n",
"class UnitCommitmentData:\n",
" demand: float\n",
" pmin: np.ndarray\n",
" pmax: np.ndarray\n",
" cfix: np.ndarray\n",
" cvar: np.ndarray"
" pmin: List[float]\n",
" pmax: List[float]\n",
" cfix: List[float]\n",
" cvar: List[float]"
]
},
{
@ -159,28 +193,38 @@
"id": "29f55efa-0751-465a-9b0a-a821d46a3d40",
"metadata": {},
"source": [
"Next, we write a `build_uc_model` function, which converts the input data into a concrete Pyomo model."
"Next, we write a `build_uc_model` function, which converts the input data into a concrete Pyomo model. The function accepts `UnitCommitmentData`, the data structure we previously defined, or the path to a compressed pickle file containing this data."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "2f67032f-0d74-4317-b45c-19da0ec859e9",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:00:45.890126754Z",
"start_time": "2023-06-06T20:00:45.637044282Z"
}
},
"outputs": [],
"source": [
"import pyomo.environ as pe\n",
"from typing import Union\n",
"from miplearn.io import read_pkl_gz\n",
"from miplearn.solvers.pyomo import PyomoModel\n",
"\n",
"\n",
"def build_uc_model(data: Union[str, UnitCommitmentData]) -> PyomoModel:\n",
" if isinstance(data, str):\n",
" data = read_pkl_gz(data)\n",
"\n",
"def build_uc_model(data: UnitCommitmentData) -> pe.ConcreteModel:\n",
" model = pe.ConcreteModel()\n",
" n = len(data.pmin)\n",
" model.x = pe.Var(range(n), domain=pe.Binary)\n",
" model.y = pe.Var(range(n), domain=pe.NonNegativeReals)\n",
" model.obj = pe.Objective(\n",
" expr=sum(\n",
" data.cfix[i] * model.x[i] +\n",
" data.cvar[i] * model.y[i]\n",
" for i in range(n)\n",
" data.cfix[i] * model.x[i] + data.cvar[i] * model.y[i] for i in range(n)\n",
" )\n",
" )\n",
" model.eq_max_power = pe.ConstraintList()\n",
@ -191,7 +235,7 @@
" model.eq_demand = pe.Constraint(\n",
" expr=sum(model.y[i] for i in range(n)) == data.demand,\n",
" )\n",
" return model"
" return PyomoModel(model, \"gurobi_persistent\")"
]
},
{
@ -206,15 +250,56 @@
"cell_type": "code",
"execution_count": 5,
"id": "2a896f47",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:01:10.993801745Z",
"start_time": "2023-06-06T20:01:10.887580927Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Set parameter Threads to value 1\n",
"Set parameter Seed to value 42\n",
"Restricted license - for non-production use only - expires 2023-10-25\n",
"Restricted license - for non-production use only - expires 2024-10-28\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 7 rows, 6 columns and 15 nonzeros\n",
"Model fingerprint: 0x15c7a953\n",
"Variable types: 3 continuous, 3 integer (3 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 7e+01]\n",
" Objective range [2e+00, 7e+02]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [1e+02, 1e+02]\n",
"Presolve removed 2 rows and 1 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 5 rows, 5 columns, 13 nonzeros\n",
"Variable types: 0 continuous, 5 integer (3 binary)\n",
"Found heuristic solution: objective 1400.0000000\n",
"\n",
"Root relaxation: objective 1.035000e+03, 3 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 1035.00000 0 1 1400.00000 1035.00000 26.1% - 0s\n",
" 0 0 1105.71429 0 1 1400.00000 1105.71429 21.0% - 0s\n",
"* 0 0 0 1320.0000000 1320.00000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (5 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 2: 1320 1400 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 1.320000000000e+03, best bound 1.320000000000e+03, gap 0.0000%\n",
"WARNING: Cannot get reduced costs for MIP.\n",
"WARNING: Cannot get duals for MIP.\n",
"obj = 1320.0\n",
"x = [-0.0, 1.0, 1.0]\n",
"y = [0.0, 60.0, 40.0]\n"
@ -224,20 +309,18 @@
"source": [
"model = build_uc_model(\n",
" UnitCommitmentData(\n",
" demand = 100.0,\n",
" pmin = [10, 20, 30],\n",
" pmax = [50, 60, 70],\n",
" cfix = [700, 600, 500],\n",
" cvar = [1.5, 2.0, 2.5],\n",
" demand=100.0,\n",
" pmin=[10, 20, 30],\n",
" pmax=[50, 60, 70],\n",
" cfix=[700, 600, 500],\n",
" cvar=[1.5, 2.0, 2.5],\n",
" )\n",
")\n",
"\n",
"solver = pe.SolverFactory(\"gurobi_persistent\")\n",
"solver.set_instance(model)\n",
"solver.solve()\n",
"print(\"obj =\", model.obj())\n",
"print(\"x =\", [model.x[i].value for i in range(3)])\n",
"print(\"y =\", [model.y[i].value for i in range(3)])"
"model.optimize()\n",
"print(\"obj =\", model.inner.obj())\n",
"print(\"x =\", [model.inner.x[i].value for i in range(3)])\n",
"print(\"y =\", [model.inner.y[i].value for i in range(3)])"
]
},
{
@ -248,6 +331,20 @@
"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."
]
},
{
"cell_type": "markdown",
"id": "01f576e1-1790-425e-9e5c-9fa07b6f4c26",
"metadata": {},
"source": [
"<div class=\"alert alert-info\">\n",
" \n",
"Notes\n",
" \n",
"- In the example above, `PyomoModel` is just a thin wrapper around a standard Pyomo model. This wrapper allows MIPLearn to be solver- and modeling-language-agnostic. The wrapper provides only a few basic methods, such as `optimize`. For more control, and to query the solution, the original Pyomo model can be accessed through `model.inner`, as illustrated above. \n",
"- To use CPLEX or XPRESS, instead of Gurobi, replace `gurobi_persistent` by `cplex_persistent` or `xpress_persistent` in the `build_uc_model`. Note that only persistent Pyomo solvers are currently supported. Pull requests adding support for other types of solver are very welcome.\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "cf60c1dd",
@ -255,7 +352,7 @@
"source": [
"## Generating training data\n",
"\n",
"Although Gurobi could solve the small example above in a fraction of a second, it gets slower for larger and more complex versions of the problem. If this is a problem that needs to be solved frequently, as it is often the case in practice, it could make sense to spend some time upfront generating a **trained** version of Gurobi, which can solve new instances (similar to the ones it was trained on) faster.\n",
"Although Gurobi could solve the small example above in a fraction of a second, it gets slower for larger and more complex versions of the problem. If this is a problem that needs to be solved frequently, as it is often the case in practice, it could make sense to spend some time upfront generating a **trained** solver, which can optimize new instances (similar to the ones it was trained on) faster.\n",
"\n",
"In the following, we will use MIPLearn to train machine learning models that is able to predict the optimal solution for instances that follow a given probability distribution, then it will provide this predicted solution to Gurobi as a warm start. Before we can train the model, we need to collect training data by solving a large number of instances. In real-world situations, we may construct these training instances based on historical data. In this tutorial, we will construct them using a random instance generator:"
]
@ -264,13 +361,19 @@
"cell_type": "code",
"execution_count": 6,
"id": "5eb09fab",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:02:27.324208900Z",
"start_time": "2023-06-06T20:02:26.990044230Z"
}
},
"outputs": [],
"source": [
"from scipy.stats import uniform\n",
"from typing import List\n",
"import random\n",
"\n",
"\n",
"def random_uc_data(samples: int, n: int, seed: int = 42) -> List[UnitCommitmentData]:\n",
" random.seed(seed)\n",
" np.random.seed(seed)\n",
@ -280,13 +383,13 @@
" cvar = uniform(loc=1.25, scale=0.25).rvs(n)\n",
" return [\n",
" UnitCommitmentData(\n",
" demand = pmax.sum() * uniform(loc=0.5, scale=0.25).rvs(),\n",
" pmin = pmin,\n",
" pmax = pmax,\n",
" cfix = cfix,\n",
" cvar = cvar,\n",
" demand=pmax.sum() * uniform(loc=0.5, scale=0.25).rvs(),\n",
" pmin=pmin,\n",
" pmax=pmax,\n",
" cfix=cfix,\n",
" cvar=cvar,\n",
" )\n",
" for i in range(samples)\n",
" for _ in range(samples)\n",
" ]"
]
},
@ -297,20 +400,26 @@
"source": [
"In this example, for simplicity, only the demands change from one instance to the next. We could also have randomized the costs, production limits or even the number of units. 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",
"\n",
"Now we generate 500 instances of this problem, each one with 50 generators, and we use 450 of these instances for training. After generating the instances, we write them to individual files. MIPLearn uses files during the training process because, for large-scale optimization problems, it is often impractical to hold in memory the entire training data, as well as the concrete Pyomo models. 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. The code below generates the files `uc/train/00000.pkl.gz`, `uc/train/00001.pkl.gz`, etc., which contain the input data in compressed (gzipped) pickle format."
"Now we generate 500 instances of this problem, each one with 50 generators, and we use 450 of these instances for training. After generating the instances, we write them to individual files. MIPLearn uses files during the training process because, for large-scale optimization problems, it is often impractical to hold in memory the entire training data, as well as the concrete Pyomo models. Files also make it much easier to solve multiple instances simultaneously, potentially on multiple machines. The code below generates the files `uc/train/00000.pkl.gz`, `uc/train/00001.pkl.gz`, etc., which contain the input data in compressed (gzipped) pickle format."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "6156752c",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:03:04.782830561Z",
"start_time": "2023-06-06T20:03:04.530421396Z"
}
},
"outputs": [],
"source": [
"from miplearn import save\n",
"data = random_uc_data(samples=500, n=50)\n",
"train_files = save(data[0:450], \"uc/train/\")\n",
"test_files = save(data[450:500], \"uc/test/\")"
"from miplearn.io import write_pkl_gz\n",
"\n",
"data = random_uc_data(samples=500, n=500)\n",
"train_data = write_pkl_gz(data[0:450], \"uc/train\")\n",
"test_data = write_pkl_gz(data[450:500], \"uc/test\")"
]
},
{
@ -318,115 +427,180 @@
"id": "b17af877",
"metadata": {},
"source": [
"Finally, we use `LearningSolver` to solve all the training instances. `LearningSolver` is the main component provided by MIPLearn, which integrates MIP solvers and ML. The optimal solutions, along with other useful training data, are stored in HDF5 files `uc/train/00000.h5`, `uc/train/00001.h5`, etc."
"Finally, we use `BasicCollector` to collect the optimal solutions and other useful training data for all training instances. The data is stored in HDF5 files `uc/train/00000.h5`, `uc/train/00001.h5`, etc. The optimization models are also exported to compressed MPS files `uc/train/00000.mps.gz`, `uc/train/00001.mps.gz`, etc."
]
},
{
"cell_type": "code",
"execution_count": 12,
"execution_count": 8,
"id": "7623f002",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:03:35.571497019Z",
"start_time": "2023-06-06T20:03:25.804104036Z"
}
},
"outputs": [],
"source": [
"from miplearn import LearningSolver\n",
"solver = LearningSolver()\n",
"solver.solve(train_files, build_uc_model);"
"from miplearn.collectors.basic import BasicCollector\n",
"\n",
"bc = BasicCollector()\n",
"bc.collect(train_data, build_uc_model, n_jobs=4)"
]
},
{
"cell_type": "markdown",
"id": "2f24ee83",
"id": "c42b1be1-9723-4827-82d8-974afa51ef9f",
"metadata": {},
"source": [
"## Solving test instances\n",
"## Training and solving test instances"
]
},
{
"cell_type": "markdown",
"id": "a33c6aa4-f0b8-4ccb-9935-01f7d7de2a1c",
"metadata": {},
"source": [
"With training data in hand, we can now design and train a machine learning model to accelerate solver performance. In this tutorial, for illustration purposes, we will use ML to generate a good warm start using $k$-nearest neighbors. More specifically, the strategy is to:\n",
"\n",
"1. Memorize the optimal solutions of all training instances;\n",
"2. Given a test instance, find the 25 most similar training instances, based on constraint right-hand sides;\n",
"3. Merge their optimal solutions into a single partial solution; specifically, only assign values to the binary variables that agree unanimously.\n",
"4. Provide this partial solution to the solver as a warm start.\n",
"\n",
"With training data in hand, we can now fit the ML models, using the `LearningSolver.fit` method, then solve the test instances with `LearningSolver.solve`, as shown below. The `tee=True` parameter asks MIPLearn to print the solver log to the screen."
"This simple strategy can be implemented as shown below, using `MemorizingPrimalComponent`. For more advanced strategies, and for the usage of more advanced classifiers, see the user guide."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "c8385030",
"id": "435f7bf8-4b09-4889-b1ec-b7b56e7d8ed2",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:05:20.497772794Z",
"start_time": "2023-06-06T20:05:20.484821405Z"
}
},
"outputs": [],
"source": [
"from sklearn.neighbors import KNeighborsClassifier\n",
"from miplearn.components.primal.actions import SetWarmStart\n",
"from miplearn.components.primal.mem import (\n",
" MemorizingPrimalComponent,\n",
" MergeTopSolutions,\n",
")\n",
"from miplearn.extractors.fields import H5FieldsExtractor\n",
"\n",
"comp = MemorizingPrimalComponent(\n",
" clf=KNeighborsClassifier(n_neighbors=25),\n",
" extractor=H5FieldsExtractor(\n",
" instance_fields=[\"static_constr_rhs\"],\n",
" ),\n",
" constructor=MergeTopSolutions(25, [0.0, 1.0]),\n",
" action=SetWarmStart(),\n",
")"
]
},
{
"cell_type": "markdown",
"id": "9536e7e4-0b0d-49b0-bebd-4a848f839e94",
"metadata": {},
"source": [
"Having defined the ML strategy, we next construct `LearningSolver`, train the ML component and optimize one of the test instances."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "9d13dd50-3dcf-4673-a757-6f44dcc0dedf",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:05:22.672002339Z",
"start_time": "2023-06-06T20:05:21.447466634Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Set parameter LogFile to value \"/tmp/tmpvbaqbyty.log\"\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 9.5.1 build v9.5.1rc2 (linux64)\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 1 threads\n",
"Optimize a model with 101 rows, 100 columns and 250 nonzeros\n",
"Model fingerprint: 0x8de73876\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x5e67c6ee\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [2e+07, 2e+07]\n",
"Presolve removed 100 rows and 50 columns\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 1 rows, 50 columns, 50 nonzeros\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
" 0 5.7349081e+08 1.044003e+04 0.000000e+00 0s\n",
" 1 6.8268465e+08 0.000000e+00 0.000000e+00 0s\n",
"\n",
"Solved in 1 iterations and 0.00 seconds (0.00 work units)\n",
"Optimal objective 6.826846503e+08\n",
"Set parameter LogFile to value \"\"\n",
"Set parameter LogFile to value \"/tmp/tmp48j6n35b.log\"\n",
"Gurobi Optimizer version 9.5.1 build v9.5.1rc2 (linux64)\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 1 threads\n",
"Optimize a model with 101 rows, 100 columns and 250 nonzeros\n",
"Model fingerprint: 0x200d64ba\n",
"Variable types: 50 continuous, 50 integer (50 binary)\n",
" 0 6.6166537e+09 5.648803e+04 0.000000e+00 0s\n",
" 1 8.2906219e+09 0.000000e+00 0.000000e+00 0s\n",
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.290621916e+09\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0xa4a7961e\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [2e+07, 2e+07]\n",
" RHS range [3e+08, 3e+08]\n",
"\n",
"User MIP start produced solution with objective 6.84841e+08 (0.00s)\n",
"Loaded user MIP start with objective 6.84841e+08\n",
"User MIP start produced solution with objective 8.30129e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29184e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29146e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29146e+09 (0.02s)\n",
"Loaded user MIP start with objective 8.29146e+09\n",
"\n",
"Presolve time: 0.00s\n",
"Presolved: 101 rows, 100 columns, 250 nonzeros\n",
"Variable types: 50 continuous, 50 integer (50 binary)\n",
"Presolve time: 0.01s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
"Root relaxation: objective 6.826847e+08, 56 iterations, 0.00 seconds (0.00 work units)\n",
"Root relaxation: objective 8.290622e+09, 512 iterations, 0.01 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 6.8268e+08 0 1 6.8484e+08 6.8268e+08 0.31% - 0s\n",
" 0 0 6.8315e+08 0 3 6.8484e+08 6.8315e+08 0.25% - 0s\n",
" 0 0 6.8315e+08 0 1 6.8484e+08 6.8315e+08 0.25% - 0s\n",
" 0 0 6.8315e+08 0 3 6.8484e+08 6.8315e+08 0.25% - 0s\n",
" 0 0 6.8315e+08 0 4 6.8484e+08 6.8315e+08 0.25% - 0s\n",
" 0 0 6.8315e+08 0 4 6.8484e+08 6.8315e+08 0.25% - 0s\n",
" 0 2 6.8327e+08 0 4 6.8484e+08 6.8327e+08 0.23% - 0s\n",
" 0 0 8.2906e+09 0 1 8.2915e+09 8.2906e+09 0.01% - 0s\n",
"\n",
"Cutting planes:\n",
" Flow cover: 3\n",
" Cover: 1\n",
" Flow cover: 2\n",
"\n",
"Explored 32 nodes (155 simplex iterations) in 0.02 seconds (0.00 work units)\n",
"Thread count was 1 (of 32 available processors)\n",
"Explored 1 nodes (512 simplex iterations) in 0.09 seconds (0.01 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 1: 6.84841e+08 \n",
"Solution count 3: 8.29146e+09 8.29184e+09 8.30129e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 6.848411655488e+08, best bound 6.848411655488e+08, gap 0.0000%\n",
"Set parameter LogFile to value \"\"\n",
"Best objective 8.291459497797e+09, best bound 8.290645029670e+09, gap 0.0098%\n",
"WARNING: Cannot get reduced costs for MIP.\n",
"WARNING: Cannot get duals for MIP.\n"
]
}
],
"source": [
"solver_ml = LearningSolver()\n",
"solver_ml.fit(train_files, build_uc_model)\n",
"solver_ml.solve(test_files[0:1], build_uc_model, tee=True);"
"from miplearn.solvers.learning import LearningSolver\n",
"\n",
"solver_ml = LearningSolver(components=[comp])\n",
"solver_ml.fit(train_data)\n",
"solver_ml.optimize(test_data[0], build_uc_model);"
]
},
{
@ -434,100 +608,105 @@
"id": "61da6dad-7f56-4edb-aa26-c00eb5f946c0",
"metadata": {},
"source": [
"By examining the solve log above, specifically the line `Loaded user MIP start with objective...`, we can see that MIPLearn was able to construct an initial solution which turned out to be the optimal solution to the problem. Now let us repeat the code above, but using an untrained solver. Note that the `fit` line is omitted."
"By examining the solve log above, specifically the line `Loaded user MIP start with objective...`, we can see that MIPLearn was able to construct an initial solution which turned out to be very close to the optimal solution to the problem. Now let us repeat the code above, but a solver which does not apply any ML strategies. Note that our previously-defined component is not provided."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "33d15d6c-6db4-477f-bd4b-fe8e84e5f023",
"metadata": {},
"execution_count": 11,
"id": "2ff391ed-e855-4228-aa09-a7641d8c2893",
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:05:46.969575966Z",
"start_time": "2023-06-06T20:05:46.420803286Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Set parameter LogFile to value \"/tmp/tmp3uhhdurw.log\"\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 9.5.1 build v9.5.1rc2 (linux64)\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 1 threads\n",
"Optimize a model with 101 rows, 100 columns and 250 nonzeros\n",
"Model fingerprint: 0x8de73876\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x5e67c6ee\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [2e+07, 2e+07]\n",
"Presolve removed 100 rows and 50 columns\n",
"Presolve time: 0.00s\n",
"Presolved: 1 rows, 50 columns, 50 nonzeros\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.01s\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
" 0 5.7349081e+08 1.044003e+04 0.000000e+00 0s\n",
" 1 6.8268465e+08 0.000000e+00 0.000000e+00 0s\n",
" 0 6.6166537e+09 5.648803e+04 0.000000e+00 0s\n",
" 1 8.2906219e+09 0.000000e+00 0.000000e+00 0s\n",
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 6.826846503e+08\n",
"Set parameter LogFile to value \"\"\n",
"Set parameter LogFile to value \"/tmp/tmp18aqg2ic.log\"\n",
"Gurobi Optimizer version 9.5.1 build v9.5.1rc2 (linux64)\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 1 threads\n",
"Optimize a model with 101 rows, 100 columns and 250 nonzeros\n",
"Model fingerprint: 0xb90d1075\n",
"Variable types: 50 continuous, 50 integer (50 binary)\n",
"Optimal objective 8.290621916e+09\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x8a0f9587\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [2e+07, 2e+07]\n",
"Found heuristic solution: objective 8.056576e+08\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve time: 0.00s\n",
"Presolved: 101 rows, 100 columns, 250 nonzeros\n",
"Variable types: 50 continuous, 50 integer (50 binary)\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Found heuristic solution: objective 9.757128e+09\n",
"\n",
"Root relaxation: objective 6.826847e+08, 56 iterations, 0.00 seconds (0.00 work units)\n",
"Root relaxation: objective 8.290622e+09, 512 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 6.8268e+08 0 1 8.0566e+08 6.8268e+08 15.3% - 0s\n",
"H 0 0 7.099498e+08 6.8268e+08 3.84% - 0s\n",
" 0 0 6.8315e+08 0 3 7.0995e+08 6.8315e+08 3.78% - 0s\n",
"H 0 0 6.883227e+08 6.8315e+08 0.75% - 0s\n",
" 0 0 6.8352e+08 0 4 6.8832e+08 6.8352e+08 0.70% - 0s\n",
" 0 0 6.8352e+08 0 4 6.8832e+08 6.8352e+08 0.70% - 0s\n",
" 0 0 6.8352e+08 0 1 6.8832e+08 6.8352e+08 0.70% - 0s\n",
"H 0 0 6.862582e+08 6.8352e+08 0.40% - 0s\n",
" 0 0 6.8352e+08 0 4 6.8626e+08 6.8352e+08 0.40% - 0s\n",
" 0 0 6.8352e+08 0 4 6.8626e+08 6.8352e+08 0.40% - 0s\n",
" 0 0 6.8352e+08 0 1 6.8626e+08 6.8352e+08 0.40% - 0s\n",
" 0 0 6.8352e+08 0 3 6.8626e+08 6.8352e+08 0.40% - 0s\n",
" 0 0 6.8352e+08 0 4 6.8626e+08 6.8352e+08 0.40% - 0s\n",
" 0 0 6.8352e+08 0 4 6.8626e+08 6.8352e+08 0.40% - 0s\n",
" 0 2 6.8354e+08 0 4 6.8626e+08 6.8354e+08 0.40% - 0s\n",
"* 18 5 6 6.849018e+08 6.8413e+08 0.11% 3.1 0s\n",
"H 24 1 6.848412e+08 6.8426e+08 0.09% 3.2 0s\n",
" 0 0 8.2906e+09 0 1 9.7571e+09 8.2906e+09 15.0% - 0s\n",
"H 0 0 8.298273e+09 8.2906e+09 0.09% - 0s\n",
" 0 0 8.2907e+09 0 4 8.2983e+09 8.2907e+09 0.09% - 0s\n",
" 0 0 8.2907e+09 0 1 8.2983e+09 8.2907e+09 0.09% - 0s\n",
" 0 0 8.2907e+09 0 4 8.2983e+09 8.2907e+09 0.09% - 0s\n",
"H 0 0 8.293980e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2907e+09 0 5 8.2940e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2907e+09 0 1 8.2940e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2907e+09 0 2 8.2940e+09 8.2907e+09 0.04% - 0s\n",
" 0 0 8.2908e+09 0 1 8.2940e+09 8.2908e+09 0.04% - 0s\n",
" 0 0 8.2908e+09 0 4 8.2940e+09 8.2908e+09 0.04% - 0s\n",
" 0 0 8.2908e+09 0 4 8.2940e+09 8.2908e+09 0.04% - 0s\n",
"H 0 0 8.291465e+09 8.2908e+09 0.01% - 0s\n",
"\n",
"Cutting planes:\n",
" Gomory: 1\n",
" Flow cover: 2\n",
" Gomory: 2\n",
" MIR: 1\n",
"\n",
"Explored 30 nodes (217 simplex iterations) in 0.02 seconds (0.00 work units)\n",
"Thread count was 1 (of 32 available processors)\n",
"Explored 1 nodes (1025 simplex iterations) in 0.08 seconds (0.03 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 6: 6.84841e+08 6.84902e+08 6.86258e+08 ... 8.05658e+08\n",
"Solution count 4: 8.29147e+09 8.29398e+09 8.29827e+09 9.75713e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 6.848411655488e+08, best bound 6.848411655488e+08, gap 0.0000%\n",
"Set parameter LogFile to value \"\"\n",
"Best objective 8.291465302389e+09, best bound 8.290781665333e+09, gap 0.0082%\n",
"WARNING: Cannot get reduced costs for MIP.\n",
"WARNING: Cannot get duals for MIP.\n"
]
}
],
"source": [
"solver_baseline = LearningSolver()\n",
"solver_baseline.solve(test_files[0:1], build_uc_model, tee=True);"
"solver_baseline = LearningSolver(components=[])\n",
"solver_baseline.fit(train_data)\n",
"solver_baseline.optimize(test_data[0], build_uc_model);"
]
},
{
@ -535,19 +714,7 @@
"id": "b6d37b88-9fcc-43ee-ac1e-2a7b1e51a266",
"metadata": {},
"source": [
"In the log above, the `MIP start` line is missing, and Gurobi had to start with a significantly inferior initial solution. The solver was still able to find the optimal solution at the end, but it required using its own internal heuristic procedures. In this example, because we solve very small optimization problems, there was almost no difference in terms of running time. For larger problems, however, the difference can be significant. See benchmarks for more details.\n",
"\n",
"<div class=\"alert alert-info\">\n",
"Note\n",
" \n",
"In addition to partial initial solutions, MIPLearn is also able to predict lazy constraints, cutting planes and branching priorities. See the next tutorials for more details.\n",
"</div>\n",
"\n",
"<div class=\"alert alert-info\">\n",
"Note\n",
" \n",
"It is not necessary to specify what ML models to use. MIPLearn, by default, will try a number of classical ML models and will choose the one that performs the best, based on k-fold cross validation. MIPLearn is also able to automatically collect features based on the MIP formulation of the problem and the solution to the LP relaxation, among other things, so it does not require handcrafted features. If you do want to customize the models and features, however, that is also possible, as we will see in a later tutorial.\n",
"</div>"
"In the log above, the `MIP start` line is missing, and Gurobi had to start with a significantly inferior initial solution. The solver was still able to find the optimal solution at the end, but it required using its own internal heuristic procedures. In this example, because we solve very small optimization problems, there was almost no difference in terms of running time, but the difference can be significant for larger problems."
]
},
{
@ -564,32 +731,109 @@
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": 12,
"id": "67a6cd18",
"metadata": {},
"metadata": {
"ExecuteTime": {
"end_time": "2023-06-06T20:06:26.913448568Z",
"start_time": "2023-06-06T20:06:26.169047914Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"obj = 903865807.3536932\n",
" x = [1.0, 1.0, 1.0, 1.0, 1.0]\n",
" y = [1105176.593734543, 1891284.5155055337, 1708177.4224033852, 1438329.610189608, 535496.3347187206]\n"
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x2dfe4e1c\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.01s\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
" 0 6.5917580e+09 5.627453e+04 0.000000e+00 0s\n",
" 1 8.2535968e+09 0.000000e+00 0.000000e+00 0s\n",
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.253596777e+09\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x20637200\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
" Objective range [1e+00, 6e+07]\n",
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"\n",
"User MIP start produced solution with objective 8.25814e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25512e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.04s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.04s)\n",
"Loaded user MIP start with objective 8.25459e+09\n",
"\n",
"Presolve time: 0.01s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
"Root relaxation: objective 8.253597e+09, 512 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 8.2536e+09 0 1 8.2546e+09 8.2536e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 3 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 1 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 4 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2537e+09 0 4 8.2546e+09 8.2537e+09 0.01% - 0s\n",
" 0 0 8.2538e+09 0 4 8.2546e+09 8.2538e+09 0.01% - 0s\n",
" 0 0 8.2538e+09 0 5 8.2546e+09 8.2538e+09 0.01% - 0s\n",
" 0 0 8.2538e+09 0 6 8.2546e+09 8.2538e+09 0.01% - 0s\n",
"\n",
"Cutting planes:\n",
" Cover: 1\n",
" MIR: 2\n",
" StrongCG: 1\n",
" Flow cover: 1\n",
"\n",
"Explored 1 nodes (575 simplex iterations) in 0.11 seconds (0.01 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"\n",
"Solution count 3: 8.25459e+09 8.25512e+09 8.25814e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 8.254590409970e+09, best bound 8.253768093811e+09, gap 0.0100%\n",
"WARNING: Cannot get reduced costs for MIP.\n",
"WARNING: Cannot get duals for MIP.\n",
"obj = 8254590409.96973\n",
" x = [1.0, 1.0, 0.0, 1.0, 1.0]\n",
" y = [935662.0949263407, 1604270.0218116897, 0.0, 1369560.835229226, 602828.5321028307]\n"
]
}
],
"source": [
"# Construct model using previously defined functions\n",
"data = random_uc_data(samples=1, n=50)[0]\n",
"data = random_uc_data(samples=1, n=500)[0]\n",
"model = build_uc_model(data)\n",
"\n",
"# Solve model using ML + Gurobi\n",
"solver_ml.solve(model)\n",
"\n",
"# Print part of the optimal solution\n",
"print(\"obj =\", model.obj())\n",
"print(\" x =\", [model.x[i].value for i in range(5)])\n",
"print(\" y =\", [model.y[i].value for i in range(5)])"
"solver_ml.optimize(model)\n",
"print(\"obj =\", model.inner.obj())\n",
"print(\" x =\", [model.inner.x[i].value for i in range(5)])\n",
"print(\" y =\", [model.inner.y[i].value for i in range(5)])"
]
},
{
@ -603,7 +847,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save