mirror of
https://github.com/ANL-CEEESA/MIPLearn.git
synced 2025-12-06 09:28:51 -06:00
Update docs
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en" data-content_root="../../">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>2. Getting started (Gurobipy) — MIPLearn 0.4</title>
|
||||
|
||||
<link href="../../_static/css/theme.css" rel="stylesheet" />
|
||||
@@ -22,21 +22,27 @@
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=362ab14a" />
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/sphinx-book-theme.acff12b8f9c144ce68a297486a2fa670.css?v=b0dfe17c" />
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/nbsphinx-code-cells.css?v=2aa19091" />
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/custom.css?v=f8244a84" />
|
||||
<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 src="../../_static/documentation_options.js?v=751a5dd3"></script>
|
||||
<script src="../../_static/doctools.js?v=888ff710"></script>
|
||||
<script src="../../_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<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?v=7c4c3336"></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>
|
||||
<script>window.MathJax = {"tex": {"inlineMath": [["$", "$"], ["\\(", "\\)"]], "processEscapes": true}, "options": {"ignoreHtmlClass": "tex2jax_ignore|mathjax_ignore|document", "processHtmlClass": "tex2jax_process|mathjax_process|math|output_area"}}</script>
|
||||
<script defer="defer" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></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/" />
|
||||
@@ -68,7 +74,7 @@
|
||||
<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" role="heading">
|
||||
<p class="caption">
|
||||
<span class="caption-text">
|
||||
Tutorials
|
||||
</span>
|
||||
@@ -95,7 +101,7 @@
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="caption" role="heading">
|
||||
<p class="caption">
|
||||
<span class="caption-text">
|
||||
User Guide
|
||||
</span>
|
||||
@@ -127,7 +133,7 @@
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="caption" role="heading">
|
||||
<p class="caption">
|
||||
<span class="caption-text">
|
||||
Python API Reference
|
||||
</span>
|
||||
@@ -266,10 +272,10 @@
|
||||
|
||||
<div>
|
||||
|
||||
<section id="Getting-started-(Gurobipy)">
|
||||
<h1><span class="section-number">2. </span>Getting started (Gurobipy)<a class="headerlink" href="#Getting-started-(Gurobipy)" title="Link to this heading">¶</a></h1>
|
||||
<section id="Introduction">
|
||||
<h2><span class="section-number">2.1. </span>Introduction<a class="headerlink" href="#Introduction" title="Link to this heading">¶</a></h2>
|
||||
<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>
|
||||
@@ -285,29 +291,25 @@
|
||||
<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>
|
||||
</section>
|
||||
<section id="Installation">
|
||||
<h2><span class="section-number">2.2. </span>Installation<a class="headerlink" href="#Installation" title="Link to this heading">¶</a></h2>
|
||||
</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="highlight-none notranslate"><div class="highlight"><pre><span></span>$ pip install MIPLearn==0.4
|
||||
</pre></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="highlight-none notranslate"><div class="highlight"><pre><span></span>$ pip install 'gurobipy>=10,<10.1'
|
||||
<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.9+ 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="highlight-none notranslate"><div class="highlight"><pre><span></span>$ pip install MIPLearn~=0.4
|
||||
</pre></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>
|
||||
</section>
|
||||
<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="Link to this heading">¶</a></h2>
|
||||
</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>
|
||||
@@ -330,19 +332,19 @@
|
||||
<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">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>
|
||||
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span>from dataclasses import dataclass
|
||||
from typing import List
|
||||
|
||||
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
|
||||
import numpy as np
|
||||
|
||||
|
||||
<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>
|
||||
@dataclass
|
||||
class UnitCommitmentData:
|
||||
demand: float
|
||||
pmin: List[float]
|
||||
pmax: List[float]
|
||||
cfix: List[float]
|
||||
cvar: List[float]
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -351,28 +353,28 @@
|
||||
<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">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>
|
||||
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span>import gurobipy as gp
|
||||
from gurobipy import GRB, quicksum
|
||||
from typing import Union
|
||||
from miplearn.io import read_pkl_gz
|
||||
from miplearn.solvers.gurobi import GurobiModel
|
||||
|
||||
|
||||
<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">-></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>
|
||||
def build_uc_model(data: Union[str, UnitCommitmentData]) -> GurobiModel:
|
||||
if isinstance(data, str):
|
||||
data = read_pkl_gz(data)
|
||||
|
||||
<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">"x"</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">"y"</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="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"><=</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">>=</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>
|
||||
model = gp.Model()
|
||||
n = len(data.pmin)
|
||||
x = model._x = model.addVars(n, vtype=GRB.BINARY, name="x")
|
||||
y = model._y = model.addVars(n, name="y")
|
||||
model.setObjective(
|
||||
quicksum(data.cfix[i] * x[i] + data.cvar[i] * y[i] for i in range(n))
|
||||
)
|
||||
model.addConstrs(y[i] <= data.pmax[i] * x[i] for i in range(n))
|
||||
model.addConstrs(y[i] >= data.pmin[i] * x[i] for i in range(n))
|
||||
model.addConstr(quicksum(y[i] for i in range(n)) == data.demand)
|
||||
return GurobiModel(model)
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -381,20 +383,20 @@
|
||||
<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="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>
|
||||
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span>model = build_uc_model(
|
||||
UnitCommitmentData(
|
||||
demand=100.0,
|
||||
pmin=[10, 20, 30],
|
||||
pmax=[50, 60, 70],
|
||||
cfix=[700, 600, 500],
|
||||
cvar=[1.5, 2.0, 2.5],
|
||||
)
|
||||
)
|
||||
|
||||
<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">"obj ="</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">"x ="</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">"y ="</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>
|
||||
model.optimize()
|
||||
print("obj =", model.inner.objVal)
|
||||
print("x =", [model.inner._x[i].x for i in range(3)])
|
||||
print("y =", [model.inner._y[i].x for i in range(3)])
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -455,9 +457,9 @@ y = [0.0, 60.0, 40.0]
|
||||
<li><p>To ensure training data consistency, MIPLearn requires all decision variables to have names.</p></li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<section id="Generating-training-data">
|
||||
<h2><span class="section-number">2.4. </span>Generating training data<a class="headerlink" href="#Generating-training-data" title="Link to this heading">¶</a></h2>
|
||||
</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>
|
||||
@@ -465,28 +467,28 @@ random instance generator:</p>
|
||||
<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">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>
|
||||
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span>from scipy.stats import uniform
|
||||
from typing import List
|
||||
import random
|
||||
|
||||
|
||||
<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">-></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>
|
||||
def random_uc_data(samples: int, n: int, seed: int = 42) -> List[UnitCommitmentData]:
|
||||
random.seed(seed)
|
||||
np.random.seed(seed)
|
||||
pmin = uniform(loc=100_000.0, scale=400_000.0).rvs(n)
|
||||
pmax = pmin * uniform(loc=2.0, scale=2.5).rvs(n)
|
||||
cfix = pmin * uniform(loc=100.0, scale=25.0).rvs(n)
|
||||
cvar = uniform(loc=1.25, scale=0.25).rvs(n)
|
||||
return [
|
||||
UnitCommitmentData(
|
||||
demand=pmax.sum() * uniform(loc=0.5, scale=0.25).rvs(),
|
||||
pmin=pmin,
|
||||
pmax=pmax,
|
||||
cfix=cfix,
|
||||
cvar=cvar,
|
||||
)
|
||||
for _ in range(samples)
|
||||
]
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -497,11 +499,11 @@ machines. The code below generates the files <code class="docutils literal notra
|
||||
<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">miplearn.io</span> <span class="kn">import</span> <span class="n">write_pkl_gz</span>
|
||||
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span>from miplearn.io import write_pkl_gz
|
||||
|
||||
<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">"uc/train"</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">"uc/test"</span><span class="p">)</span>
|
||||
data = random_uc_data(samples=500, n=500)
|
||||
train_data = write_pkl_gz(data[0:450], "uc/train")
|
||||
test_data = write_pkl_gz(data[450:500], "uc/test")
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -510,16 +512,16 @@ machines. The code below generates the files <code class="docutils literal notra
|
||||
<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.collectors.basic</span> <span class="kn">import</span> <span class="n">BasicCollector</span>
|
||||
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span>from miplearn.collectors.basic import BasicCollector
|
||||
|
||||
<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>
|
||||
bc = BasicCollector()
|
||||
bc.collect(train_data, build_uc_model)
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<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="Link to this heading">¶</a></h2>
|
||||
</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>
|
||||
@@ -532,22 +534,22 @@ machines. The code below generates the files <code class="docutils literal notra
|
||||
<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">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>
|
||||
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span>from sklearn.neighbors import KNeighborsClassifier
|
||||
from miplearn.components.primal.actions import SetWarmStart
|
||||
from miplearn.components.primal.mem import (
|
||||
MemorizingPrimalComponent,
|
||||
MergeTopSolutions,
|
||||
)
|
||||
from miplearn.extractors.fields import H5FieldsExtractor
|
||||
|
||||
<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">"static_constr_rhs"</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>
|
||||
comp = MemorizingPrimalComponent(
|
||||
clf=KNeighborsClassifier(n_neighbors=25),
|
||||
extractor=H5FieldsExtractor(
|
||||
instance_fields=["static_constr_rhs"],
|
||||
),
|
||||
constructor=MergeTopSolutions(25, [0.0, 1.0]),
|
||||
action=SetWarmStart(),
|
||||
)
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -556,11 +558,11 @@ machines. The code below generates the files <code class="docutils literal notra
|
||||
<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.solvers.learning</span> <span class="kn">import</span> <span class="n">LearningSolver</span>
|
||||
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span>from miplearn.solvers.learning import LearningSolver
|
||||
|
||||
<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>
|
||||
solver_ml = LearningSolver(components=[comp])
|
||||
solver_ml.fit(train_data)
|
||||
solver_ml.optimize(test_data[0], build_uc_model)
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -654,9 +656,9 @@ User-callback calls 193, time in user-callback 0.00 sec
|
||||
<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="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>
|
||||
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span>solver_baseline = LearningSolver(components=[])
|
||||
solver_baseline.fit(train_data)
|
||||
solver_baseline.optimize(test_data[0], build_uc_model);
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -747,20 +749,20 @@ User-callback calls 708, 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>
|
||||
</section>
|
||||
<section id="Accessing-the-solution">
|
||||
<h2><span class="section-number">2.6. </span>Accessing the solution<a class="headerlink" href="#Accessing-the-solution" title="Link to this heading">¶</a></h2>
|
||||
</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. 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>[10]:
|
||||
</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">"obj ="</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">"x ="</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">"y ="</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>
|
||||
<div class="input_area highlight-ipython3 notranslate"><div class="highlight"><pre><span></span>data = random_uc_data(samples=1, n=500)[0]
|
||||
model = build_uc_model(data)
|
||||
solver_ml.optimize(model)
|
||||
print("obj =", model.inner.objVal)
|
||||
print("x =", [model.inner._x[i].x for i in range(3)])
|
||||
print("y =", [model.inner._y[i].x for i in range(3)])
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -855,8 +857,8 @@ y = [935662.0949262811, 1604270.0218116897, 0.0]
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user