mirror of
https://github.com/ANL-CEEESA/MIPLearn.git
synced 2025-12-06 09:28:51 -06:00
Update 0.2 docs
This commit is contained in:
928
0.2/api/miplearn/solvers/gurobi.html
Normal file
928
0.2/api/miplearn/solvers/gurobi.html
Normal file
@@ -0,0 +1,928 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.7.0" />
|
||||
<title>miplearn.solvers.gurobi API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
|
||||
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>miplearn.solvers.gurobi</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
import logging
|
||||
import re
|
||||
import sys
|
||||
from io import StringIO
|
||||
from random import randint
|
||||
from typing import List, Any, Dict, Optional
|
||||
|
||||
from miplearn.instance import Instance
|
||||
from miplearn.solvers import _RedirectOutput
|
||||
from miplearn.solvers.internal import (
|
||||
InternalSolver,
|
||||
LPSolveStats,
|
||||
IterationCallback,
|
||||
LazyCallback,
|
||||
MIPSolveStats,
|
||||
)
|
||||
from miplearn.types import VarIndex, SolverParams, Solution
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GurobiSolver(InternalSolver):
|
||||
"""
|
||||
An InternalSolver backed by Gurobi's Python API (without Pyomo).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
params: Optional[SolverParams]
|
||||
Parameters to pass to Gurobi. For example, `params={"MIPGap": 1e-3}`
|
||||
sets the gap tolerance to 1e-3.
|
||||
lazy_cb_frequency: int
|
||||
If 1, calls lazy constraint callbacks whenever an integer solution
|
||||
is found. If 2, calls it also at every node, after solving the
|
||||
LP relaxation of that node.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
params: Optional[SolverParams] = None,
|
||||
lazy_cb_frequency: int = 1,
|
||||
) -> None:
|
||||
import gurobipy
|
||||
|
||||
if params is None:
|
||||
params = {}
|
||||
params["InfUnbdInfo"] = True
|
||||
|
||||
self.gp = gurobipy
|
||||
self.instance: Optional[Instance] = None
|
||||
self.model: Optional["gurobipy.Model"] = None
|
||||
self.params: SolverParams = params
|
||||
self._all_vars: Dict = {}
|
||||
self._bin_vars: Optional[Dict[str, Dict[VarIndex, "gurobipy.Var"]]] = None
|
||||
self.cb_where: Optional[int] = None
|
||||
|
||||
assert lazy_cb_frequency in [1, 2]
|
||||
if lazy_cb_frequency == 1:
|
||||
self.lazy_cb_where = [self.gp.GRB.Callback.MIPSOL]
|
||||
else:
|
||||
self.lazy_cb_where = [
|
||||
self.gp.GRB.Callback.MIPSOL,
|
||||
self.gp.GRB.Callback.MIPNODE,
|
||||
]
|
||||
|
||||
def set_instance(
|
||||
self,
|
||||
instance: Instance,
|
||||
model: Any = None,
|
||||
) -> None:
|
||||
self._raise_if_callback()
|
||||
if model is None:
|
||||
model = instance.to_model()
|
||||
assert isinstance(model, self.gp.Model)
|
||||
self.instance = instance
|
||||
self.model = model
|
||||
self.model.update()
|
||||
self._update_vars()
|
||||
|
||||
def _raise_if_callback(self) -> None:
|
||||
if self.cb_where is not None:
|
||||
raise Exception("method cannot be called from a callback")
|
||||
|
||||
def _update_vars(self) -> None:
|
||||
assert self.model is not None
|
||||
self._all_vars = {}
|
||||
self._bin_vars = {}
|
||||
idx: VarIndex
|
||||
for var in self.model.getVars():
|
||||
m = re.search(r"([^[]*)\[(.*)]", var.varName)
|
||||
if m is None:
|
||||
name = var.varName
|
||||
idx = [0]
|
||||
else:
|
||||
name = m.group(1)
|
||||
parts = m.group(2).split(",")
|
||||
idx = [int(k) if k.isdecimal else k for k in parts]
|
||||
if len(idx) == 1:
|
||||
idx = idx[0]
|
||||
if name not in self._all_vars:
|
||||
self._all_vars[name] = {}
|
||||
self._all_vars[name][idx] = var
|
||||
if var.vtype != "C":
|
||||
if name not in self._bin_vars:
|
||||
self._bin_vars[name] = {}
|
||||
self._bin_vars[name][idx] = var
|
||||
|
||||
def _apply_params(self, streams: List[Any]) -> None:
|
||||
assert self.model is not None
|
||||
with _RedirectOutput(streams):
|
||||
for (name, value) in self.params.items():
|
||||
self.model.setParam(name, value)
|
||||
if "seed" not in [k.lower() for k in self.params.keys()]:
|
||||
self.model.setParam("Seed", randint(0, 1_000_000))
|
||||
|
||||
def solve_lp(
|
||||
self,
|
||||
tee: bool = False,
|
||||
) -> LPSolveStats:
|
||||
self._raise_if_callback()
|
||||
streams: List[Any] = [StringIO()]
|
||||
if tee:
|
||||
streams += [sys.stdout]
|
||||
self._apply_params(streams)
|
||||
assert self.model is not None
|
||||
assert self._bin_vars is not None
|
||||
for (varname, vardict) in self._bin_vars.items():
|
||||
for (idx, var) in vardict.items():
|
||||
var.vtype = self.gp.GRB.CONTINUOUS
|
||||
var.lb = 0.0
|
||||
var.ub = 1.0
|
||||
with _RedirectOutput(streams):
|
||||
self.model.optimize()
|
||||
for (varname, vardict) in self._bin_vars.items():
|
||||
for (idx, var) in vardict.items():
|
||||
var.vtype = self.gp.GRB.BINARY
|
||||
log = streams[0].getvalue()
|
||||
opt_value = None
|
||||
if not self.is_infeasible():
|
||||
opt_value = self.model.objVal
|
||||
return {
|
||||
"Optimal value": opt_value,
|
||||
"Log": log,
|
||||
}
|
||||
|
||||
def solve(
|
||||
self,
|
||||
tee: bool = False,
|
||||
iteration_cb: IterationCallback = None,
|
||||
lazy_cb: LazyCallback = None,
|
||||
) -> MIPSolveStats:
|
||||
self._raise_if_callback()
|
||||
assert self.model is not None
|
||||
|
||||
def cb_wrapper(cb_model, cb_where):
|
||||
try:
|
||||
self.cb_where = cb_where
|
||||
if cb_where in self.lazy_cb_where:
|
||||
lazy_cb(self, self.model)
|
||||
except:
|
||||
logger.exception("callback error")
|
||||
finally:
|
||||
self.cb_where = None
|
||||
|
||||
if lazy_cb:
|
||||
self.params["LazyConstraints"] = 1
|
||||
total_wallclock_time = 0
|
||||
total_nodes = 0
|
||||
streams: List[Any] = [StringIO()]
|
||||
if tee:
|
||||
streams += [sys.stdout]
|
||||
self._apply_params(streams)
|
||||
if iteration_cb is None:
|
||||
iteration_cb = lambda: False
|
||||
while True:
|
||||
with _RedirectOutput(streams):
|
||||
if lazy_cb is None:
|
||||
self.model.optimize()
|
||||
else:
|
||||
self.model.optimize(cb_wrapper)
|
||||
total_wallclock_time += self.model.runtime
|
||||
total_nodes += int(self.model.nodeCount)
|
||||
should_repeat = iteration_cb()
|
||||
if not should_repeat:
|
||||
break
|
||||
log = streams[0].getvalue()
|
||||
ub, lb = None, None
|
||||
sense = "min" if self.model.modelSense == 1 else "max"
|
||||
if self.model.solCount > 0:
|
||||
if self.model.modelSense == 1:
|
||||
lb = self.model.objBound
|
||||
ub = self.model.objVal
|
||||
else:
|
||||
lb = self.model.objVal
|
||||
ub = self.model.objBound
|
||||
ws_value = self._extract_warm_start_value(log)
|
||||
stats: MIPSolveStats = {
|
||||
"Lower bound": lb,
|
||||
"Upper bound": ub,
|
||||
"Wallclock time": total_wallclock_time,
|
||||
"Nodes": total_nodes,
|
||||
"Sense": sense,
|
||||
"Log": log,
|
||||
"Warm start value": ws_value,
|
||||
"LP value": None,
|
||||
}
|
||||
return stats
|
||||
|
||||
def get_solution(self) -> Optional[Solution]:
|
||||
self._raise_if_callback()
|
||||
assert self.model is not None
|
||||
if self.model.solCount == 0:
|
||||
return None
|
||||
solution: Solution = {}
|
||||
for (varname, vardict) in self._all_vars.items():
|
||||
solution[varname] = {}
|
||||
for (idx, var) in vardict.items():
|
||||
solution[varname][idx] = var.x
|
||||
return solution
|
||||
|
||||
def set_warm_start(self, solution: Solution) -> None:
|
||||
self._raise_if_callback()
|
||||
self._clear_warm_start()
|
||||
count_fixed, count_total = 0, 0
|
||||
for (varname, vardict) in solution.items():
|
||||
for (idx, value) in vardict.items():
|
||||
count_total += 1
|
||||
if value is not None:
|
||||
count_fixed += 1
|
||||
self._all_vars[varname][idx].start = value
|
||||
logger.info(
|
||||
"Setting start values for %d variables (out of %d)"
|
||||
% (count_fixed, count_total)
|
||||
)
|
||||
|
||||
def get_sense(self) -> str:
|
||||
assert self.model is not None
|
||||
if self.model.modelSense == 1:
|
||||
return "min"
|
||||
else:
|
||||
return "max"
|
||||
|
||||
def get_value(
|
||||
self,
|
||||
var_name: str,
|
||||
index: VarIndex,
|
||||
) -> Optional[float]:
|
||||
var = self._all_vars[var_name][index]
|
||||
return self._get_value(var)
|
||||
|
||||
def is_infeasible(self) -> bool:
|
||||
assert self.model is not None
|
||||
return self.model.status in [self.gp.GRB.INFEASIBLE, self.gp.GRB.INF_OR_UNBD]
|
||||
|
||||
def get_dual(self, cid: str) -> float:
|
||||
assert self.model is not None
|
||||
c = self.model.getConstrByName(cid)
|
||||
if self.is_infeasible():
|
||||
return c.farkasDual
|
||||
else:
|
||||
return c.pi
|
||||
|
||||
def _get_value(self, var: Any) -> Optional[float]:
|
||||
assert self.model is not None
|
||||
if self.cb_where == self.gp.GRB.Callback.MIPSOL:
|
||||
return self.model.cbGetSolution(var)
|
||||
elif self.cb_where == self.gp.GRB.Callback.MIPNODE:
|
||||
return self.model.cbGetNodeRel(var)
|
||||
elif self.cb_where is None:
|
||||
if self.is_infeasible():
|
||||
return None
|
||||
else:
|
||||
return var.x
|
||||
else:
|
||||
raise Exception(
|
||||
"get_value cannot be called from cb_where=%s" % self.cb_where
|
||||
)
|
||||
|
||||
def get_empty_solution(self) -> Solution:
|
||||
self._raise_if_callback()
|
||||
solution: Solution = {}
|
||||
for (varname, vardict) in self._all_vars.items():
|
||||
solution[varname] = {}
|
||||
for (idx, var) in vardict.items():
|
||||
solution[varname][idx] = None
|
||||
return solution
|
||||
|
||||
def add_constraint(
|
||||
self,
|
||||
constraint: Any,
|
||||
name: str = "",
|
||||
) -> None:
|
||||
assert self.model is not None
|
||||
if type(constraint) is tuple:
|
||||
lhs, sense, rhs, name = constraint
|
||||
if self.cb_where in [
|
||||
self.gp.GRB.Callback.MIPSOL,
|
||||
self.gp.GRB.Callback.MIPNODE,
|
||||
]:
|
||||
self.model.cbLazy(lhs, sense, rhs)
|
||||
else:
|
||||
self.model.addConstr(lhs, sense, rhs, name)
|
||||
else:
|
||||
if self.cb_where in [
|
||||
self.gp.GRB.Callback.MIPSOL,
|
||||
self.gp.GRB.Callback.MIPNODE,
|
||||
]:
|
||||
self.model.cbLazy(constraint)
|
||||
else:
|
||||
self.model.addConstr(constraint, name=name)
|
||||
|
||||
def _clear_warm_start(self) -> None:
|
||||
for (varname, vardict) in self._all_vars.items():
|
||||
for (idx, var) in vardict.items():
|
||||
var.start = self.gp.GRB.UNDEFINED
|
||||
|
||||
def fix(self, solution: Solution) -> None:
|
||||
self._raise_if_callback()
|
||||
for (varname, vardict) in solution.items():
|
||||
for (idx, value) in vardict.items():
|
||||
if value is None:
|
||||
continue
|
||||
var = self._all_vars[varname][idx]
|
||||
var.vtype = self.gp.GRB.CONTINUOUS
|
||||
var.lb = value
|
||||
var.ub = value
|
||||
|
||||
def get_constraint_ids(self):
|
||||
self._raise_if_callback()
|
||||
self.model.update()
|
||||
return [c.ConstrName for c in self.model.getConstrs()]
|
||||
|
||||
def extract_constraint(self, cid):
|
||||
self._raise_if_callback()
|
||||
constr = self.model.getConstrByName(cid)
|
||||
cobj = (self.model.getRow(constr), constr.sense, constr.RHS, constr.ConstrName)
|
||||
self.model.remove(constr)
|
||||
return cobj
|
||||
|
||||
def is_constraint_satisfied(self, cobj, tol=1e-5):
|
||||
lhs, sense, rhs, name = cobj
|
||||
if self.cb_where is not None:
|
||||
lhs_value = lhs.getConstant()
|
||||
for i in range(lhs.size()):
|
||||
var = lhs.getVar(i)
|
||||
coeff = lhs.getCoeff(i)
|
||||
lhs_value += self._get_value(var) * coeff
|
||||
else:
|
||||
lhs_value = lhs.getValue()
|
||||
if sense == "<":
|
||||
return lhs_value <= rhs + tol
|
||||
elif sense == ">":
|
||||
return lhs_value >= rhs - tol
|
||||
elif sense == "=":
|
||||
return abs(rhs - lhs_value) < abs(tol)
|
||||
else:
|
||||
raise Exception("Unknown sense: %s" % sense)
|
||||
|
||||
def get_inequality_slacks(self) -> Dict[str, float]:
|
||||
assert self.model is not None
|
||||
ineqs = [c for c in self.model.getConstrs() if c.sense != "="]
|
||||
return {c.ConstrName: c.Slack for c in ineqs}
|
||||
|
||||
def set_constraint_sense(self, cid: str, sense: str) -> None:
|
||||
assert self.model is not None
|
||||
c = self.model.getConstrByName(cid)
|
||||
c.Sense = sense
|
||||
|
||||
def get_constraint_sense(self, cid: str) -> str:
|
||||
assert self.model is not None
|
||||
c = self.model.getConstrByName(cid)
|
||||
return c.Sense
|
||||
|
||||
def relax(self) -> None:
|
||||
assert self.model is not None
|
||||
self.model = self.model.relax()
|
||||
self._update_vars()
|
||||
|
||||
def _extract_warm_start_value(self, log: str) -> Optional[float]:
|
||||
ws = self.__extract(log, "MIP start with objective ([0-9.e+-]*)")
|
||||
if ws is None:
|
||||
return None
|
||||
return float(ws)
|
||||
|
||||
@staticmethod
|
||||
def __extract(
|
||||
log: str,
|
||||
regexp: str,
|
||||
default: Optional[str] = None,
|
||||
) -> Optional[str]:
|
||||
value = default
|
||||
for line in log.splitlines():
|
||||
matches = re.findall(regexp, line)
|
||||
if len(matches) == 0:
|
||||
continue
|
||||
value = matches[0]
|
||||
return value
|
||||
|
||||
def __getstate__(self):
|
||||
return {
|
||||
"params": self.params,
|
||||
"lazy_cb_where": self.lazy_cb_where,
|
||||
}
|
||||
|
||||
def __setstate__(self, state):
|
||||
|
||||
self.params = state["params"]
|
||||
self.lazy_cb_where = state["lazy_cb_where"]
|
||||
self.instance = None
|
||||
self.model = None
|
||||
self._all_vars = None
|
||||
self._bin_vars = None
|
||||
self.cb_where = None</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="miplearn.solvers.gurobi.GurobiSolver"><code class="flex name class">
|
||||
<span>class <span class="ident">GurobiSolver</span></span>
|
||||
<span>(</span><span>params=None, lazy_cb_frequency=1)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"><p>An InternalSolver backed by Gurobi's Python API (without Pyomo).</p>
|
||||
<h2 id="parameters">Parameters</h2>
|
||||
<dl>
|
||||
<dt><strong><code>params</code></strong> : <code>Optional</code>[<code>SolverParams</code>]</dt>
|
||||
<dd>Parameters to pass to Gurobi. For example, <code>params={"MIPGap": 1e-3}</code>
|
||||
sets the gap tolerance to 1e-3.</dd>
|
||||
<dt><strong><code>lazy_cb_frequency</code></strong> : <code>int</code></dt>
|
||||
<dd>If 1, calls lazy constraint callbacks whenever an integer solution
|
||||
is found. If 2, calls it also at every node, after solving the
|
||||
LP relaxation of that node.</dd>
|
||||
</dl></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class GurobiSolver(InternalSolver):
|
||||
"""
|
||||
An InternalSolver backed by Gurobi's Python API (without Pyomo).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
params: Optional[SolverParams]
|
||||
Parameters to pass to Gurobi. For example, `params={"MIPGap": 1e-3}`
|
||||
sets the gap tolerance to 1e-3.
|
||||
lazy_cb_frequency: int
|
||||
If 1, calls lazy constraint callbacks whenever an integer solution
|
||||
is found. If 2, calls it also at every node, after solving the
|
||||
LP relaxation of that node.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
params: Optional[SolverParams] = None,
|
||||
lazy_cb_frequency: int = 1,
|
||||
) -> None:
|
||||
import gurobipy
|
||||
|
||||
if params is None:
|
||||
params = {}
|
||||
params["InfUnbdInfo"] = True
|
||||
|
||||
self.gp = gurobipy
|
||||
self.instance: Optional[Instance] = None
|
||||
self.model: Optional["gurobipy.Model"] = None
|
||||
self.params: SolverParams = params
|
||||
self._all_vars: Dict = {}
|
||||
self._bin_vars: Optional[Dict[str, Dict[VarIndex, "gurobipy.Var"]]] = None
|
||||
self.cb_where: Optional[int] = None
|
||||
|
||||
assert lazy_cb_frequency in [1, 2]
|
||||
if lazy_cb_frequency == 1:
|
||||
self.lazy_cb_where = [self.gp.GRB.Callback.MIPSOL]
|
||||
else:
|
||||
self.lazy_cb_where = [
|
||||
self.gp.GRB.Callback.MIPSOL,
|
||||
self.gp.GRB.Callback.MIPNODE,
|
||||
]
|
||||
|
||||
def set_instance(
|
||||
self,
|
||||
instance: Instance,
|
||||
model: Any = None,
|
||||
) -> None:
|
||||
self._raise_if_callback()
|
||||
if model is None:
|
||||
model = instance.to_model()
|
||||
assert isinstance(model, self.gp.Model)
|
||||
self.instance = instance
|
||||
self.model = model
|
||||
self.model.update()
|
||||
self._update_vars()
|
||||
|
||||
def _raise_if_callback(self) -> None:
|
||||
if self.cb_where is not None:
|
||||
raise Exception("method cannot be called from a callback")
|
||||
|
||||
def _update_vars(self) -> None:
|
||||
assert self.model is not None
|
||||
self._all_vars = {}
|
||||
self._bin_vars = {}
|
||||
idx: VarIndex
|
||||
for var in self.model.getVars():
|
||||
m = re.search(r"([^[]*)\[(.*)]", var.varName)
|
||||
if m is None:
|
||||
name = var.varName
|
||||
idx = [0]
|
||||
else:
|
||||
name = m.group(1)
|
||||
parts = m.group(2).split(",")
|
||||
idx = [int(k) if k.isdecimal else k for k in parts]
|
||||
if len(idx) == 1:
|
||||
idx = idx[0]
|
||||
if name not in self._all_vars:
|
||||
self._all_vars[name] = {}
|
||||
self._all_vars[name][idx] = var
|
||||
if var.vtype != "C":
|
||||
if name not in self._bin_vars:
|
||||
self._bin_vars[name] = {}
|
||||
self._bin_vars[name][idx] = var
|
||||
|
||||
def _apply_params(self, streams: List[Any]) -> None:
|
||||
assert self.model is not None
|
||||
with _RedirectOutput(streams):
|
||||
for (name, value) in self.params.items():
|
||||
self.model.setParam(name, value)
|
||||
if "seed" not in [k.lower() for k in self.params.keys()]:
|
||||
self.model.setParam("Seed", randint(0, 1_000_000))
|
||||
|
||||
def solve_lp(
|
||||
self,
|
||||
tee: bool = False,
|
||||
) -> LPSolveStats:
|
||||
self._raise_if_callback()
|
||||
streams: List[Any] = [StringIO()]
|
||||
if tee:
|
||||
streams += [sys.stdout]
|
||||
self._apply_params(streams)
|
||||
assert self.model is not None
|
||||
assert self._bin_vars is not None
|
||||
for (varname, vardict) in self._bin_vars.items():
|
||||
for (idx, var) in vardict.items():
|
||||
var.vtype = self.gp.GRB.CONTINUOUS
|
||||
var.lb = 0.0
|
||||
var.ub = 1.0
|
||||
with _RedirectOutput(streams):
|
||||
self.model.optimize()
|
||||
for (varname, vardict) in self._bin_vars.items():
|
||||
for (idx, var) in vardict.items():
|
||||
var.vtype = self.gp.GRB.BINARY
|
||||
log = streams[0].getvalue()
|
||||
opt_value = None
|
||||
if not self.is_infeasible():
|
||||
opt_value = self.model.objVal
|
||||
return {
|
||||
"Optimal value": opt_value,
|
||||
"Log": log,
|
||||
}
|
||||
|
||||
def solve(
|
||||
self,
|
||||
tee: bool = False,
|
||||
iteration_cb: IterationCallback = None,
|
||||
lazy_cb: LazyCallback = None,
|
||||
) -> MIPSolveStats:
|
||||
self._raise_if_callback()
|
||||
assert self.model is not None
|
||||
|
||||
def cb_wrapper(cb_model, cb_where):
|
||||
try:
|
||||
self.cb_where = cb_where
|
||||
if cb_where in self.lazy_cb_where:
|
||||
lazy_cb(self, self.model)
|
||||
except:
|
||||
logger.exception("callback error")
|
||||
finally:
|
||||
self.cb_where = None
|
||||
|
||||
if lazy_cb:
|
||||
self.params["LazyConstraints"] = 1
|
||||
total_wallclock_time = 0
|
||||
total_nodes = 0
|
||||
streams: List[Any] = [StringIO()]
|
||||
if tee:
|
||||
streams += [sys.stdout]
|
||||
self._apply_params(streams)
|
||||
if iteration_cb is None:
|
||||
iteration_cb = lambda: False
|
||||
while True:
|
||||
with _RedirectOutput(streams):
|
||||
if lazy_cb is None:
|
||||
self.model.optimize()
|
||||
else:
|
||||
self.model.optimize(cb_wrapper)
|
||||
total_wallclock_time += self.model.runtime
|
||||
total_nodes += int(self.model.nodeCount)
|
||||
should_repeat = iteration_cb()
|
||||
if not should_repeat:
|
||||
break
|
||||
log = streams[0].getvalue()
|
||||
ub, lb = None, None
|
||||
sense = "min" if self.model.modelSense == 1 else "max"
|
||||
if self.model.solCount > 0:
|
||||
if self.model.modelSense == 1:
|
||||
lb = self.model.objBound
|
||||
ub = self.model.objVal
|
||||
else:
|
||||
lb = self.model.objVal
|
||||
ub = self.model.objBound
|
||||
ws_value = self._extract_warm_start_value(log)
|
||||
stats: MIPSolveStats = {
|
||||
"Lower bound": lb,
|
||||
"Upper bound": ub,
|
||||
"Wallclock time": total_wallclock_time,
|
||||
"Nodes": total_nodes,
|
||||
"Sense": sense,
|
||||
"Log": log,
|
||||
"Warm start value": ws_value,
|
||||
"LP value": None,
|
||||
}
|
||||
return stats
|
||||
|
||||
def get_solution(self) -> Optional[Solution]:
|
||||
self._raise_if_callback()
|
||||
assert self.model is not None
|
||||
if self.model.solCount == 0:
|
||||
return None
|
||||
solution: Solution = {}
|
||||
for (varname, vardict) in self._all_vars.items():
|
||||
solution[varname] = {}
|
||||
for (idx, var) in vardict.items():
|
||||
solution[varname][idx] = var.x
|
||||
return solution
|
||||
|
||||
def set_warm_start(self, solution: Solution) -> None:
|
||||
self._raise_if_callback()
|
||||
self._clear_warm_start()
|
||||
count_fixed, count_total = 0, 0
|
||||
for (varname, vardict) in solution.items():
|
||||
for (idx, value) in vardict.items():
|
||||
count_total += 1
|
||||
if value is not None:
|
||||
count_fixed += 1
|
||||
self._all_vars[varname][idx].start = value
|
||||
logger.info(
|
||||
"Setting start values for %d variables (out of %d)"
|
||||
% (count_fixed, count_total)
|
||||
)
|
||||
|
||||
def get_sense(self) -> str:
|
||||
assert self.model is not None
|
||||
if self.model.modelSense == 1:
|
||||
return "min"
|
||||
else:
|
||||
return "max"
|
||||
|
||||
def get_value(
|
||||
self,
|
||||
var_name: str,
|
||||
index: VarIndex,
|
||||
) -> Optional[float]:
|
||||
var = self._all_vars[var_name][index]
|
||||
return self._get_value(var)
|
||||
|
||||
def is_infeasible(self) -> bool:
|
||||
assert self.model is not None
|
||||
return self.model.status in [self.gp.GRB.INFEASIBLE, self.gp.GRB.INF_OR_UNBD]
|
||||
|
||||
def get_dual(self, cid: str) -> float:
|
||||
assert self.model is not None
|
||||
c = self.model.getConstrByName(cid)
|
||||
if self.is_infeasible():
|
||||
return c.farkasDual
|
||||
else:
|
||||
return c.pi
|
||||
|
||||
def _get_value(self, var: Any) -> Optional[float]:
|
||||
assert self.model is not None
|
||||
if self.cb_where == self.gp.GRB.Callback.MIPSOL:
|
||||
return self.model.cbGetSolution(var)
|
||||
elif self.cb_where == self.gp.GRB.Callback.MIPNODE:
|
||||
return self.model.cbGetNodeRel(var)
|
||||
elif self.cb_where is None:
|
||||
if self.is_infeasible():
|
||||
return None
|
||||
else:
|
||||
return var.x
|
||||
else:
|
||||
raise Exception(
|
||||
"get_value cannot be called from cb_where=%s" % self.cb_where
|
||||
)
|
||||
|
||||
def get_empty_solution(self) -> Solution:
|
||||
self._raise_if_callback()
|
||||
solution: Solution = {}
|
||||
for (varname, vardict) in self._all_vars.items():
|
||||
solution[varname] = {}
|
||||
for (idx, var) in vardict.items():
|
||||
solution[varname][idx] = None
|
||||
return solution
|
||||
|
||||
def add_constraint(
|
||||
self,
|
||||
constraint: Any,
|
||||
name: str = "",
|
||||
) -> None:
|
||||
assert self.model is not None
|
||||
if type(constraint) is tuple:
|
||||
lhs, sense, rhs, name = constraint
|
||||
if self.cb_where in [
|
||||
self.gp.GRB.Callback.MIPSOL,
|
||||
self.gp.GRB.Callback.MIPNODE,
|
||||
]:
|
||||
self.model.cbLazy(lhs, sense, rhs)
|
||||
else:
|
||||
self.model.addConstr(lhs, sense, rhs, name)
|
||||
else:
|
||||
if self.cb_where in [
|
||||
self.gp.GRB.Callback.MIPSOL,
|
||||
self.gp.GRB.Callback.MIPNODE,
|
||||
]:
|
||||
self.model.cbLazy(constraint)
|
||||
else:
|
||||
self.model.addConstr(constraint, name=name)
|
||||
|
||||
def _clear_warm_start(self) -> None:
|
||||
for (varname, vardict) in self._all_vars.items():
|
||||
for (idx, var) in vardict.items():
|
||||
var.start = self.gp.GRB.UNDEFINED
|
||||
|
||||
def fix(self, solution: Solution) -> None:
|
||||
self._raise_if_callback()
|
||||
for (varname, vardict) in solution.items():
|
||||
for (idx, value) in vardict.items():
|
||||
if value is None:
|
||||
continue
|
||||
var = self._all_vars[varname][idx]
|
||||
var.vtype = self.gp.GRB.CONTINUOUS
|
||||
var.lb = value
|
||||
var.ub = value
|
||||
|
||||
def get_constraint_ids(self):
|
||||
self._raise_if_callback()
|
||||
self.model.update()
|
||||
return [c.ConstrName for c in self.model.getConstrs()]
|
||||
|
||||
def extract_constraint(self, cid):
|
||||
self._raise_if_callback()
|
||||
constr = self.model.getConstrByName(cid)
|
||||
cobj = (self.model.getRow(constr), constr.sense, constr.RHS, constr.ConstrName)
|
||||
self.model.remove(constr)
|
||||
return cobj
|
||||
|
||||
def is_constraint_satisfied(self, cobj, tol=1e-5):
|
||||
lhs, sense, rhs, name = cobj
|
||||
if self.cb_where is not None:
|
||||
lhs_value = lhs.getConstant()
|
||||
for i in range(lhs.size()):
|
||||
var = lhs.getVar(i)
|
||||
coeff = lhs.getCoeff(i)
|
||||
lhs_value += self._get_value(var) * coeff
|
||||
else:
|
||||
lhs_value = lhs.getValue()
|
||||
if sense == "<":
|
||||
return lhs_value <= rhs + tol
|
||||
elif sense == ">":
|
||||
return lhs_value >= rhs - tol
|
||||
elif sense == "=":
|
||||
return abs(rhs - lhs_value) < abs(tol)
|
||||
else:
|
||||
raise Exception("Unknown sense: %s" % sense)
|
||||
|
||||
def get_inequality_slacks(self) -> Dict[str, float]:
|
||||
assert self.model is not None
|
||||
ineqs = [c for c in self.model.getConstrs() if c.sense != "="]
|
||||
return {c.ConstrName: c.Slack for c in ineqs}
|
||||
|
||||
def set_constraint_sense(self, cid: str, sense: str) -> None:
|
||||
assert self.model is not None
|
||||
c = self.model.getConstrByName(cid)
|
||||
c.Sense = sense
|
||||
|
||||
def get_constraint_sense(self, cid: str) -> str:
|
||||
assert self.model is not None
|
||||
c = self.model.getConstrByName(cid)
|
||||
return c.Sense
|
||||
|
||||
def relax(self) -> None:
|
||||
assert self.model is not None
|
||||
self.model = self.model.relax()
|
||||
self._update_vars()
|
||||
|
||||
def _extract_warm_start_value(self, log: str) -> Optional[float]:
|
||||
ws = self.__extract(log, "MIP start with objective ([0-9.e+-]*)")
|
||||
if ws is None:
|
||||
return None
|
||||
return float(ws)
|
||||
|
||||
@staticmethod
|
||||
def __extract(
|
||||
log: str,
|
||||
regexp: str,
|
||||
default: Optional[str] = None,
|
||||
) -> Optional[str]:
|
||||
value = default
|
||||
for line in log.splitlines():
|
||||
matches = re.findall(regexp, line)
|
||||
if len(matches) == 0:
|
||||
continue
|
||||
value = matches[0]
|
||||
return value
|
||||
|
||||
def __getstate__(self):
|
||||
return {
|
||||
"params": self.params,
|
||||
"lazy_cb_where": self.lazy_cb_where,
|
||||
}
|
||||
|
||||
def __setstate__(self, state):
|
||||
|
||||
self.params = state["params"]
|
||||
self.lazy_cb_where = state["lazy_cb_where"]
|
||||
self.instance = None
|
||||
self.model = None
|
||||
self._all_vars = None
|
||||
self._bin_vars = None
|
||||
self.cb_where = None</code></pre>
|
||||
</details>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li><a title="miplearn.solvers.internal.InternalSolver" href="internal.html#miplearn.solvers.internal.InternalSolver">InternalSolver</a></li>
|
||||
<li>abc.ABC</li>
|
||||
</ul>
|
||||
<h3>Inherited members</h3>
|
||||
<ul class="hlist">
|
||||
<li><code><b><a title="miplearn.solvers.internal.InternalSolver" href="internal.html#miplearn.solvers.internal.InternalSolver">InternalSolver</a></b></code>:
|
||||
<ul class="hlist">
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.add_constraint" href="internal.html#miplearn.solvers.internal.InternalSolver.add_constraint">add_constraint</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.extract_constraint" href="internal.html#miplearn.solvers.internal.InternalSolver.extract_constraint">extract_constraint</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.fix" href="internal.html#miplearn.solvers.internal.InternalSolver.fix">fix</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_constraint_ids" href="internal.html#miplearn.solvers.internal.InternalSolver.get_constraint_ids">get_constraint_ids</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_constraint_sense" href="internal.html#miplearn.solvers.internal.InternalSolver.get_constraint_sense">get_constraint_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_dual" href="internal.html#miplearn.solvers.internal.InternalSolver.get_dual">get_dual</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_empty_solution" href="internal.html#miplearn.solvers.internal.InternalSolver.get_empty_solution">get_empty_solution</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_inequality_slacks" href="internal.html#miplearn.solvers.internal.InternalSolver.get_inequality_slacks">get_inequality_slacks</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_sense" href="internal.html#miplearn.solvers.internal.InternalSolver.get_sense">get_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_solution" href="internal.html#miplearn.solvers.internal.InternalSolver.get_solution">get_solution</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_value" href="internal.html#miplearn.solvers.internal.InternalSolver.get_value">get_value</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.is_constraint_satisfied" href="internal.html#miplearn.solvers.internal.InternalSolver.is_constraint_satisfied">is_constraint_satisfied</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.is_infeasible" href="internal.html#miplearn.solvers.internal.InternalSolver.is_infeasible">is_infeasible</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.relax" href="internal.html#miplearn.solvers.internal.InternalSolver.relax">relax</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.set_branching_priorities" href="internal.html#miplearn.solvers.internal.InternalSolver.set_branching_priorities">set_branching_priorities</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.set_constraint_sense" href="internal.html#miplearn.solvers.internal.InternalSolver.set_constraint_sense">set_constraint_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.set_instance" href="internal.html#miplearn.solvers.internal.InternalSolver.set_instance">set_instance</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.set_warm_start" href="internal.html#miplearn.solvers.internal.InternalSolver.set_warm_start">set_warm_start</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.solve" href="internal.html#miplearn.solvers.internal.InternalSolver.solve">solve</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.solve_lp" href="internal.html#miplearn.solvers.internal.InternalSolver.solve_lp">solve_lp</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="miplearn.solvers" href="index.html">miplearn.solvers</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="miplearn.solvers.gurobi.GurobiSolver" href="#miplearn.solvers.gurobi.GurobiSolver">GurobiSolver</a></code></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.7.0</a>.</p>
|
||||
</footer>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad()</script>
|
||||
</body>
|
||||
</html>
|
||||
123
0.2/api/miplearn/solvers/index.html
Normal file
123
0.2/api/miplearn/solvers/index.html
Normal file
@@ -0,0 +1,123 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.7.0" />
|
||||
<title>miplearn.solvers API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
|
||||
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>miplearn.solvers</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
import logging
|
||||
import sys
|
||||
from typing import Any, List
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class _RedirectOutput:
|
||||
def __init__(self, streams: List[Any]):
|
||||
self.streams = streams
|
||||
|
||||
def write(self, data: Any) -> None:
|
||||
for stream in self.streams:
|
||||
stream.write(data)
|
||||
|
||||
def flush(self) -> None:
|
||||
for stream in self.streams:
|
||||
stream.flush()
|
||||
|
||||
def __enter__(self):
|
||||
self._original_stdout = sys.stdout
|
||||
self._original_stderr = sys.stderr
|
||||
sys.stdout = self
|
||||
sys.stderr = self
|
||||
return self
|
||||
|
||||
def __exit__(self, _type, _value, _traceback):
|
||||
sys.stdout = self._original_stdout
|
||||
sys.stderr = self._original_stderr</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-submodules">Sub-modules</h2>
|
||||
<dl>
|
||||
<dt><code class="name"><a title="miplearn.solvers.gurobi" href="gurobi.html">miplearn.solvers.gurobi</a></code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="miplearn.solvers.internal" href="internal.html">miplearn.solvers.internal</a></code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="miplearn.solvers.learning" href="learning.html">miplearn.solvers.learning</a></code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="miplearn.solvers.pyomo" href="pyomo/index.html">miplearn.solvers.pyomo</a></code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="miplearn.solvers.tests" href="tests/index.html">miplearn.solvers.tests</a></code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="miplearn" href="../index.html">miplearn</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-submodules">Sub-modules</a></h3>
|
||||
<ul>
|
||||
<li><code><a title="miplearn.solvers.gurobi" href="gurobi.html">miplearn.solvers.gurobi</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal" href="internal.html">miplearn.solvers.internal</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.learning" href="learning.html">miplearn.solvers.learning</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo" href="pyomo/index.html">miplearn.solvers.pyomo</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.tests" href="tests/index.html">miplearn.solvers.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.7.0</a>.</p>
|
||||
</footer>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad()</script>
|
||||
</body>
|
||||
</html>
|
||||
1142
0.2/api/miplearn/solvers/internal.html
Normal file
1142
0.2/api/miplearn/solvers/internal.html
Normal file
File diff suppressed because it is too large
Load Diff
1058
0.2/api/miplearn/solvers/learning.html
Normal file
1058
0.2/api/miplearn/solvers/learning.html
Normal file
File diff suppressed because it is too large
Load Diff
730
0.2/api/miplearn/solvers/pyomo/base.html
Normal file
730
0.2/api/miplearn/solvers/pyomo/base.html
Normal file
@@ -0,0 +1,730 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.7.0" />
|
||||
<title>miplearn.solvers.pyomo.base API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
|
||||
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>miplearn.solvers.pyomo.base</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
import logging
|
||||
import re
|
||||
import sys
|
||||
from io import StringIO
|
||||
from typing import Any, List, Dict, Optional
|
||||
|
||||
import pyomo
|
||||
from pyomo import environ as pe
|
||||
from pyomo.core import Var, Constraint
|
||||
from pyomo.opt import TerminationCondition
|
||||
from pyomo.opt.base.solvers import SolverFactory
|
||||
|
||||
from miplearn.instance import Instance
|
||||
from miplearn.solvers import _RedirectOutput
|
||||
from miplearn.solvers.internal import (
|
||||
InternalSolver,
|
||||
LPSolveStats,
|
||||
IterationCallback,
|
||||
LazyCallback,
|
||||
MIPSolveStats,
|
||||
)
|
||||
from miplearn.types import VarIndex, SolverParams, Solution
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BasePyomoSolver(InternalSolver):
|
||||
"""
|
||||
Base class for all Pyomo solvers.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
solver_factory: SolverFactory,
|
||||
params: SolverParams,
|
||||
) -> None:
|
||||
self.instance: Optional[Instance] = None
|
||||
self.model: Optional[pe.ConcreteModel] = None
|
||||
self._all_vars: List[pe.Var] = []
|
||||
self._bin_vars: List[pe.Var] = []
|
||||
self._is_warm_start_available: bool = False
|
||||
self._pyomo_solver: SolverFactory = solver_factory
|
||||
self._obj_sense: str = "min"
|
||||
self._varname_to_var: Dict[str, pe.Var] = {}
|
||||
self._cname_to_constr: Dict[str, pe.Constraint] = {}
|
||||
self._termination_condition: str = ""
|
||||
|
||||
for (key, value) in params.items():
|
||||
self._pyomo_solver.options[key] = value
|
||||
|
||||
def solve_lp(
|
||||
self,
|
||||
tee: bool = False,
|
||||
) -> LPSolveStats:
|
||||
self.relax()
|
||||
streams: List[Any] = [StringIO()]
|
||||
if tee:
|
||||
streams += [sys.stdout]
|
||||
with _RedirectOutput(streams):
|
||||
results = self._pyomo_solver.solve(tee=True)
|
||||
self._restore_integrality()
|
||||
opt_value = None
|
||||
if not self.is_infeasible():
|
||||
opt_value = results["Problem"][0]["Lower bound"]
|
||||
return {
|
||||
"Optimal value": opt_value,
|
||||
"Log": streams[0].getvalue(),
|
||||
}
|
||||
|
||||
def _restore_integrality(self) -> None:
|
||||
for var in self._bin_vars:
|
||||
var.domain = pyomo.core.base.set_types.Binary
|
||||
self._pyomo_solver.update_var(var)
|
||||
|
||||
def solve(
|
||||
self,
|
||||
tee: bool = False,
|
||||
iteration_cb: IterationCallback = None,
|
||||
lazy_cb: LazyCallback = None,
|
||||
) -> MIPSolveStats:
|
||||
if lazy_cb is not None:
|
||||
raise Exception("lazy callback not supported")
|
||||
total_wallclock_time = 0
|
||||
streams: List[Any] = [StringIO()]
|
||||
if tee:
|
||||
streams += [sys.stdout]
|
||||
if iteration_cb is None:
|
||||
iteration_cb = lambda: False
|
||||
while True:
|
||||
logger.debug("Solving MIP...")
|
||||
with _RedirectOutput(streams):
|
||||
results = self._pyomo_solver.solve(
|
||||
tee=True,
|
||||
warmstart=self._is_warm_start_available,
|
||||
)
|
||||
total_wallclock_time += results["Solver"][0]["Wallclock time"]
|
||||
should_repeat = iteration_cb()
|
||||
if not should_repeat:
|
||||
break
|
||||
log = streams[0].getvalue()
|
||||
node_count = self._extract_node_count(log)
|
||||
ws_value = self._extract_warm_start_value(log)
|
||||
self._termination_condition = results["Solver"][0]["Termination condition"]
|
||||
lb, ub = None, None
|
||||
if not self.is_infeasible():
|
||||
lb = results["Problem"][0]["Lower bound"]
|
||||
ub = results["Problem"][0]["Upper bound"]
|
||||
stats: MIPSolveStats = {
|
||||
"Lower bound": lb,
|
||||
"Upper bound": ub,
|
||||
"Wallclock time": total_wallclock_time,
|
||||
"Sense": self._obj_sense,
|
||||
"Log": log,
|
||||
"Nodes": node_count,
|
||||
"Warm start value": ws_value,
|
||||
"LP value": None,
|
||||
}
|
||||
return stats
|
||||
|
||||
def get_solution(self) -> Optional[Solution]:
|
||||
assert self.model is not None
|
||||
if self.is_infeasible():
|
||||
return None
|
||||
solution: Solution = {}
|
||||
for var in self.model.component_objects(Var):
|
||||
solution[str(var)] = {}
|
||||
for index in var:
|
||||
if var[index].fixed:
|
||||
continue
|
||||
solution[str(var)][index] = var[index].value
|
||||
return solution
|
||||
|
||||
def set_warm_start(self, solution: Solution) -> None:
|
||||
self._clear_warm_start()
|
||||
count_total, count_fixed = 0, 0
|
||||
for var_name in solution:
|
||||
var = self._varname_to_var[var_name]
|
||||
for index in solution[var_name]:
|
||||
count_total += 1
|
||||
var[index].value = solution[var_name][index]
|
||||
if solution[var_name][index] is not None:
|
||||
count_fixed += 1
|
||||
if count_fixed > 0:
|
||||
self._is_warm_start_available = True
|
||||
logger.info(
|
||||
"Setting start values for %d variables (out of %d)"
|
||||
% (count_fixed, count_total)
|
||||
)
|
||||
|
||||
def set_instance(
|
||||
self,
|
||||
instance: Instance,
|
||||
model: Any = None,
|
||||
) -> None:
|
||||
if model is None:
|
||||
model = instance.to_model()
|
||||
assert isinstance(model, pe.ConcreteModel)
|
||||
self.instance = instance
|
||||
self.model = model
|
||||
self._pyomo_solver.set_instance(model)
|
||||
self._update_obj()
|
||||
self._update_vars()
|
||||
self._update_constrs()
|
||||
|
||||
def get_value(self, var_name: str, index: VarIndex) -> Optional[float]:
|
||||
if self.is_infeasible():
|
||||
return None
|
||||
else:
|
||||
var = self._varname_to_var[var_name]
|
||||
return var[index].value
|
||||
|
||||
def get_empty_solution(self) -> Solution:
|
||||
assert self.model is not None
|
||||
solution: Solution = {}
|
||||
for var in self.model.component_objects(Var):
|
||||
svar = str(var)
|
||||
solution[svar] = {}
|
||||
for index in var:
|
||||
if var[index].fixed:
|
||||
continue
|
||||
solution[svar][index] = None
|
||||
return solution
|
||||
|
||||
def _clear_warm_start(self) -> None:
|
||||
for var in self._all_vars:
|
||||
if not var.fixed:
|
||||
var.value = None
|
||||
self._is_warm_start_available = False
|
||||
|
||||
def _update_obj(self) -> None:
|
||||
self._obj_sense = "max"
|
||||
if self._pyomo_solver._objective.sense == pyomo.core.kernel.objective.minimize:
|
||||
self._obj_sense = "min"
|
||||
|
||||
def _update_vars(self) -> None:
|
||||
assert self.model is not None
|
||||
self._all_vars = []
|
||||
self._bin_vars = []
|
||||
self._varname_to_var = {}
|
||||
for var in self.model.component_objects(Var):
|
||||
self._varname_to_var[var.name] = var
|
||||
for idx in var:
|
||||
self._all_vars += [var[idx]]
|
||||
if var[idx].domain == pyomo.core.base.set_types.Binary:
|
||||
self._bin_vars += [var[idx]]
|
||||
|
||||
def _update_constrs(self) -> None:
|
||||
assert self.model is not None
|
||||
self._cname_to_constr = {}
|
||||
for constr in self.model.component_objects(Constraint):
|
||||
self._cname_to_constr[constr.name] = constr
|
||||
|
||||
def fix(self, solution):
|
||||
count_total, count_fixed = 0, 0
|
||||
for varname in solution:
|
||||
for index in solution[varname]:
|
||||
var = self._varname_to_var[varname]
|
||||
count_total += 1
|
||||
if solution[varname][index] is None:
|
||||
continue
|
||||
count_fixed += 1
|
||||
var[index].fix(solution[varname][index])
|
||||
self._pyomo_solver.update_var(var[index])
|
||||
logger.info(
|
||||
"Fixing values for %d variables (out of %d)"
|
||||
% (
|
||||
count_fixed,
|
||||
count_total,
|
||||
)
|
||||
)
|
||||
|
||||
def add_constraint(self, constraint):
|
||||
self._pyomo_solver.add_constraint(constraint)
|
||||
self._update_constrs()
|
||||
|
||||
@staticmethod
|
||||
def __extract(
|
||||
log: str,
|
||||
regexp: Optional[str],
|
||||
default: Optional[str] = None,
|
||||
) -> Optional[str]:
|
||||
if regexp is None:
|
||||
return default
|
||||
value = default
|
||||
for line in log.splitlines():
|
||||
matches = re.findall(regexp, line)
|
||||
if len(matches) == 0:
|
||||
continue
|
||||
value = matches[0]
|
||||
return value
|
||||
|
||||
def _extract_warm_start_value(self, log: str) -> Optional[float]:
|
||||
value = self.__extract(log, self._get_warm_start_regexp())
|
||||
if value is None:
|
||||
return None
|
||||
return float(value)
|
||||
|
||||
def _extract_node_count(self, log: str) -> Optional[int]:
|
||||
value = self.__extract(log, self._get_node_count_regexp())
|
||||
if value is None:
|
||||
return None
|
||||
return int(value)
|
||||
|
||||
def get_constraint_ids(self):
|
||||
return list(self._cname_to_constr.keys())
|
||||
|
||||
def _get_warm_start_regexp(self) -> Optional[str]:
|
||||
return None
|
||||
|
||||
def _get_node_count_regexp(self) -> Optional[str]:
|
||||
return None
|
||||
|
||||
def relax(self) -> None:
|
||||
for var in self._bin_vars:
|
||||
lb, ub = var.bounds
|
||||
var.setlb(lb)
|
||||
var.setub(ub)
|
||||
var.domain = pyomo.core.base.set_types.Reals
|
||||
self._pyomo_solver.update_var(var)
|
||||
|
||||
def get_inequality_slacks(self) -> Dict[str, float]:
|
||||
result: Dict[str, float] = {}
|
||||
for (cname, cobj) in self._cname_to_constr.items():
|
||||
if cobj.equality:
|
||||
continue
|
||||
result[cname] = cobj.slack()
|
||||
return result
|
||||
|
||||
def get_constraint_sense(self, cid: str) -> str:
|
||||
cobj = self._cname_to_constr[cid]
|
||||
has_ub = cobj.has_ub()
|
||||
has_lb = cobj.has_lb()
|
||||
assert (not has_lb) or (not has_ub), "range constraints not supported"
|
||||
if has_lb:
|
||||
return ">"
|
||||
elif has_ub:
|
||||
return "<"
|
||||
else:
|
||||
return "="
|
||||
|
||||
def set_constraint_sense(self, cid: str, sense: str) -> None:
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def extract_constraint(self, cid: str) -> Constraint:
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def is_constraint_satisfied(self, cobj: Constraint) -> bool:
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def is_infeasible(self) -> bool:
|
||||
return self._termination_condition == TerminationCondition.infeasible
|
||||
|
||||
def get_dual(self, cid):
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def get_sense(self) -> str:
|
||||
return self._obj_sense</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="miplearn.solvers.pyomo.base.BasePyomoSolver"><code class="flex name class">
|
||||
<span>class <span class="ident">BasePyomoSolver</span></span>
|
||||
<span>(</span><span>solver_factory, params)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"><p>Base class for all Pyomo solvers.</p></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class BasePyomoSolver(InternalSolver):
|
||||
"""
|
||||
Base class for all Pyomo solvers.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
solver_factory: SolverFactory,
|
||||
params: SolverParams,
|
||||
) -> None:
|
||||
self.instance: Optional[Instance] = None
|
||||
self.model: Optional[pe.ConcreteModel] = None
|
||||
self._all_vars: List[pe.Var] = []
|
||||
self._bin_vars: List[pe.Var] = []
|
||||
self._is_warm_start_available: bool = False
|
||||
self._pyomo_solver: SolverFactory = solver_factory
|
||||
self._obj_sense: str = "min"
|
||||
self._varname_to_var: Dict[str, pe.Var] = {}
|
||||
self._cname_to_constr: Dict[str, pe.Constraint] = {}
|
||||
self._termination_condition: str = ""
|
||||
|
||||
for (key, value) in params.items():
|
||||
self._pyomo_solver.options[key] = value
|
||||
|
||||
def solve_lp(
|
||||
self,
|
||||
tee: bool = False,
|
||||
) -> LPSolveStats:
|
||||
self.relax()
|
||||
streams: List[Any] = [StringIO()]
|
||||
if tee:
|
||||
streams += [sys.stdout]
|
||||
with _RedirectOutput(streams):
|
||||
results = self._pyomo_solver.solve(tee=True)
|
||||
self._restore_integrality()
|
||||
opt_value = None
|
||||
if not self.is_infeasible():
|
||||
opt_value = results["Problem"][0]["Lower bound"]
|
||||
return {
|
||||
"Optimal value": opt_value,
|
||||
"Log": streams[0].getvalue(),
|
||||
}
|
||||
|
||||
def _restore_integrality(self) -> None:
|
||||
for var in self._bin_vars:
|
||||
var.domain = pyomo.core.base.set_types.Binary
|
||||
self._pyomo_solver.update_var(var)
|
||||
|
||||
def solve(
|
||||
self,
|
||||
tee: bool = False,
|
||||
iteration_cb: IterationCallback = None,
|
||||
lazy_cb: LazyCallback = None,
|
||||
) -> MIPSolveStats:
|
||||
if lazy_cb is not None:
|
||||
raise Exception("lazy callback not supported")
|
||||
total_wallclock_time = 0
|
||||
streams: List[Any] = [StringIO()]
|
||||
if tee:
|
||||
streams += [sys.stdout]
|
||||
if iteration_cb is None:
|
||||
iteration_cb = lambda: False
|
||||
while True:
|
||||
logger.debug("Solving MIP...")
|
||||
with _RedirectOutput(streams):
|
||||
results = self._pyomo_solver.solve(
|
||||
tee=True,
|
||||
warmstart=self._is_warm_start_available,
|
||||
)
|
||||
total_wallclock_time += results["Solver"][0]["Wallclock time"]
|
||||
should_repeat = iteration_cb()
|
||||
if not should_repeat:
|
||||
break
|
||||
log = streams[0].getvalue()
|
||||
node_count = self._extract_node_count(log)
|
||||
ws_value = self._extract_warm_start_value(log)
|
||||
self._termination_condition = results["Solver"][0]["Termination condition"]
|
||||
lb, ub = None, None
|
||||
if not self.is_infeasible():
|
||||
lb = results["Problem"][0]["Lower bound"]
|
||||
ub = results["Problem"][0]["Upper bound"]
|
||||
stats: MIPSolveStats = {
|
||||
"Lower bound": lb,
|
||||
"Upper bound": ub,
|
||||
"Wallclock time": total_wallclock_time,
|
||||
"Sense": self._obj_sense,
|
||||
"Log": log,
|
||||
"Nodes": node_count,
|
||||
"Warm start value": ws_value,
|
||||
"LP value": None,
|
||||
}
|
||||
return stats
|
||||
|
||||
def get_solution(self) -> Optional[Solution]:
|
||||
assert self.model is not None
|
||||
if self.is_infeasible():
|
||||
return None
|
||||
solution: Solution = {}
|
||||
for var in self.model.component_objects(Var):
|
||||
solution[str(var)] = {}
|
||||
for index in var:
|
||||
if var[index].fixed:
|
||||
continue
|
||||
solution[str(var)][index] = var[index].value
|
||||
return solution
|
||||
|
||||
def set_warm_start(self, solution: Solution) -> None:
|
||||
self._clear_warm_start()
|
||||
count_total, count_fixed = 0, 0
|
||||
for var_name in solution:
|
||||
var = self._varname_to_var[var_name]
|
||||
for index in solution[var_name]:
|
||||
count_total += 1
|
||||
var[index].value = solution[var_name][index]
|
||||
if solution[var_name][index] is not None:
|
||||
count_fixed += 1
|
||||
if count_fixed > 0:
|
||||
self._is_warm_start_available = True
|
||||
logger.info(
|
||||
"Setting start values for %d variables (out of %d)"
|
||||
% (count_fixed, count_total)
|
||||
)
|
||||
|
||||
def set_instance(
|
||||
self,
|
||||
instance: Instance,
|
||||
model: Any = None,
|
||||
) -> None:
|
||||
if model is None:
|
||||
model = instance.to_model()
|
||||
assert isinstance(model, pe.ConcreteModel)
|
||||
self.instance = instance
|
||||
self.model = model
|
||||
self._pyomo_solver.set_instance(model)
|
||||
self._update_obj()
|
||||
self._update_vars()
|
||||
self._update_constrs()
|
||||
|
||||
def get_value(self, var_name: str, index: VarIndex) -> Optional[float]:
|
||||
if self.is_infeasible():
|
||||
return None
|
||||
else:
|
||||
var = self._varname_to_var[var_name]
|
||||
return var[index].value
|
||||
|
||||
def get_empty_solution(self) -> Solution:
|
||||
assert self.model is not None
|
||||
solution: Solution = {}
|
||||
for var in self.model.component_objects(Var):
|
||||
svar = str(var)
|
||||
solution[svar] = {}
|
||||
for index in var:
|
||||
if var[index].fixed:
|
||||
continue
|
||||
solution[svar][index] = None
|
||||
return solution
|
||||
|
||||
def _clear_warm_start(self) -> None:
|
||||
for var in self._all_vars:
|
||||
if not var.fixed:
|
||||
var.value = None
|
||||
self._is_warm_start_available = False
|
||||
|
||||
def _update_obj(self) -> None:
|
||||
self._obj_sense = "max"
|
||||
if self._pyomo_solver._objective.sense == pyomo.core.kernel.objective.minimize:
|
||||
self._obj_sense = "min"
|
||||
|
||||
def _update_vars(self) -> None:
|
||||
assert self.model is not None
|
||||
self._all_vars = []
|
||||
self._bin_vars = []
|
||||
self._varname_to_var = {}
|
||||
for var in self.model.component_objects(Var):
|
||||
self._varname_to_var[var.name] = var
|
||||
for idx in var:
|
||||
self._all_vars += [var[idx]]
|
||||
if var[idx].domain == pyomo.core.base.set_types.Binary:
|
||||
self._bin_vars += [var[idx]]
|
||||
|
||||
def _update_constrs(self) -> None:
|
||||
assert self.model is not None
|
||||
self._cname_to_constr = {}
|
||||
for constr in self.model.component_objects(Constraint):
|
||||
self._cname_to_constr[constr.name] = constr
|
||||
|
||||
def fix(self, solution):
|
||||
count_total, count_fixed = 0, 0
|
||||
for varname in solution:
|
||||
for index in solution[varname]:
|
||||
var = self._varname_to_var[varname]
|
||||
count_total += 1
|
||||
if solution[varname][index] is None:
|
||||
continue
|
||||
count_fixed += 1
|
||||
var[index].fix(solution[varname][index])
|
||||
self._pyomo_solver.update_var(var[index])
|
||||
logger.info(
|
||||
"Fixing values for %d variables (out of %d)"
|
||||
% (
|
||||
count_fixed,
|
||||
count_total,
|
||||
)
|
||||
)
|
||||
|
||||
def add_constraint(self, constraint):
|
||||
self._pyomo_solver.add_constraint(constraint)
|
||||
self._update_constrs()
|
||||
|
||||
@staticmethod
|
||||
def __extract(
|
||||
log: str,
|
||||
regexp: Optional[str],
|
||||
default: Optional[str] = None,
|
||||
) -> Optional[str]:
|
||||
if regexp is None:
|
||||
return default
|
||||
value = default
|
||||
for line in log.splitlines():
|
||||
matches = re.findall(regexp, line)
|
||||
if len(matches) == 0:
|
||||
continue
|
||||
value = matches[0]
|
||||
return value
|
||||
|
||||
def _extract_warm_start_value(self, log: str) -> Optional[float]:
|
||||
value = self.__extract(log, self._get_warm_start_regexp())
|
||||
if value is None:
|
||||
return None
|
||||
return float(value)
|
||||
|
||||
def _extract_node_count(self, log: str) -> Optional[int]:
|
||||
value = self.__extract(log, self._get_node_count_regexp())
|
||||
if value is None:
|
||||
return None
|
||||
return int(value)
|
||||
|
||||
def get_constraint_ids(self):
|
||||
return list(self._cname_to_constr.keys())
|
||||
|
||||
def _get_warm_start_regexp(self) -> Optional[str]:
|
||||
return None
|
||||
|
||||
def _get_node_count_regexp(self) -> Optional[str]:
|
||||
return None
|
||||
|
||||
def relax(self) -> None:
|
||||
for var in self._bin_vars:
|
||||
lb, ub = var.bounds
|
||||
var.setlb(lb)
|
||||
var.setub(ub)
|
||||
var.domain = pyomo.core.base.set_types.Reals
|
||||
self._pyomo_solver.update_var(var)
|
||||
|
||||
def get_inequality_slacks(self) -> Dict[str, float]:
|
||||
result: Dict[str, float] = {}
|
||||
for (cname, cobj) in self._cname_to_constr.items():
|
||||
if cobj.equality:
|
||||
continue
|
||||
result[cname] = cobj.slack()
|
||||
return result
|
||||
|
||||
def get_constraint_sense(self, cid: str) -> str:
|
||||
cobj = self._cname_to_constr[cid]
|
||||
has_ub = cobj.has_ub()
|
||||
has_lb = cobj.has_lb()
|
||||
assert (not has_lb) or (not has_ub), "range constraints not supported"
|
||||
if has_lb:
|
||||
return ">"
|
||||
elif has_ub:
|
||||
return "<"
|
||||
else:
|
||||
return "="
|
||||
|
||||
def set_constraint_sense(self, cid: str, sense: str) -> None:
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def extract_constraint(self, cid: str) -> Constraint:
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def is_constraint_satisfied(self, cobj: Constraint) -> bool:
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def is_infeasible(self) -> bool:
|
||||
return self._termination_condition == TerminationCondition.infeasible
|
||||
|
||||
def get_dual(self, cid):
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def get_sense(self) -> str:
|
||||
return self._obj_sense</code></pre>
|
||||
</details>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li><a title="miplearn.solvers.internal.InternalSolver" href="../internal.html#miplearn.solvers.internal.InternalSolver">InternalSolver</a></li>
|
||||
<li>abc.ABC</li>
|
||||
</ul>
|
||||
<h3>Subclasses</h3>
|
||||
<ul class="hlist">
|
||||
<li><a title="miplearn.solvers.pyomo.gurobi.GurobiPyomoSolver" href="gurobi.html#miplearn.solvers.pyomo.gurobi.GurobiPyomoSolver">GurobiPyomoSolver</a></li>
|
||||
<li><a title="miplearn.solvers.pyomo.cplex.CplexPyomoSolver" href="cplex.html#miplearn.solvers.pyomo.cplex.CplexPyomoSolver">CplexPyomoSolver</a></li>
|
||||
<li><a title="miplearn.solvers.pyomo.xpress.XpressPyomoSolver" href="xpress.html#miplearn.solvers.pyomo.xpress.XpressPyomoSolver">XpressPyomoSolver</a></li>
|
||||
</ul>
|
||||
<h3>Inherited members</h3>
|
||||
<ul class="hlist">
|
||||
<li><code><b><a title="miplearn.solvers.internal.InternalSolver" href="../internal.html#miplearn.solvers.internal.InternalSolver">InternalSolver</a></b></code>:
|
||||
<ul class="hlist">
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.add_constraint" href="../internal.html#miplearn.solvers.internal.InternalSolver.add_constraint">add_constraint</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.extract_constraint" href="../internal.html#miplearn.solvers.internal.InternalSolver.extract_constraint">extract_constraint</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.fix" href="../internal.html#miplearn.solvers.internal.InternalSolver.fix">fix</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_constraint_ids" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_constraint_ids">get_constraint_ids</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_constraint_sense" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_constraint_sense">get_constraint_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_dual" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_dual">get_dual</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_empty_solution" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_empty_solution">get_empty_solution</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_inequality_slacks" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_inequality_slacks">get_inequality_slacks</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_sense" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_sense">get_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_solution" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_solution">get_solution</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.get_value" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_value">get_value</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.is_constraint_satisfied" href="../internal.html#miplearn.solvers.internal.InternalSolver.is_constraint_satisfied">is_constraint_satisfied</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.is_infeasible" href="../internal.html#miplearn.solvers.internal.InternalSolver.is_infeasible">is_infeasible</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.relax" href="../internal.html#miplearn.solvers.internal.InternalSolver.relax">relax</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.set_branching_priorities" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_branching_priorities">set_branching_priorities</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.set_constraint_sense" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_constraint_sense">set_constraint_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.set_instance" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_instance">set_instance</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.set_warm_start" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_warm_start">set_warm_start</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.solve" href="../internal.html#miplearn.solvers.internal.InternalSolver.solve">solve</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.internal.InternalSolver.solve_lp" href="../internal.html#miplearn.solvers.internal.InternalSolver.solve_lp">solve_lp</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="miplearn.solvers.pyomo" href="index.html">miplearn.solvers.pyomo</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver" href="#miplearn.solvers.pyomo.base.BasePyomoSolver">BasePyomoSolver</a></code></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.7.0</a>.</p>
|
||||
</footer>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad()</script>
|
||||
</body>
|
||||
</html>
|
||||
193
0.2/api/miplearn/solvers/pyomo/cplex.html
Normal file
193
0.2/api/miplearn/solvers/pyomo/cplex.html
Normal file
@@ -0,0 +1,193 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.7.0" />
|
||||
<title>miplearn.solvers.pyomo.cplex API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
|
||||
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>miplearn.solvers.pyomo.cplex</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
from typing import Optional
|
||||
|
||||
from pyomo import environ as pe
|
||||
from scipy.stats import randint
|
||||
|
||||
from miplearn.solvers.pyomo.base import BasePyomoSolver
|
||||
from miplearn.types import SolverParams
|
||||
|
||||
|
||||
class CplexPyomoSolver(BasePyomoSolver):
|
||||
"""
|
||||
An InternalSolver that uses CPLEX and the Pyomo modeling language.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
params: dict
|
||||
Dictionary of options to pass to the Pyomo solver. For example,
|
||||
{"mip_display": 5} to increase the log verbosity.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
params: Optional[SolverParams] = None,
|
||||
) -> None:
|
||||
if params is None:
|
||||
params = {}
|
||||
if "randomseed" not in params.keys():
|
||||
params["randomseed"] = randint(low=0, high=1000).rvs()
|
||||
if "mip_display" not in params.keys():
|
||||
params["mip_display"] = 4
|
||||
super().__init__(
|
||||
solver_factory=pe.SolverFactory("cplex_persistent"),
|
||||
params=params,
|
||||
)
|
||||
|
||||
def _get_warm_start_regexp(self):
|
||||
return "MIP start .* with objective ([0-9.e+-]*)\\."
|
||||
|
||||
def _get_node_count_regexp(self):
|
||||
return "^[ *] *([0-9]+)"</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="miplearn.solvers.pyomo.cplex.CplexPyomoSolver"><code class="flex name class">
|
||||
<span>class <span class="ident">CplexPyomoSolver</span></span>
|
||||
<span>(</span><span>params=None)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"><p>An InternalSolver that uses CPLEX and the Pyomo modeling language.</p>
|
||||
<h2 id="parameters">Parameters</h2>
|
||||
<dl>
|
||||
<dt><strong><code>params</code></strong> : <code>dict</code></dt>
|
||||
<dd>Dictionary of options to pass to the Pyomo solver. For example,
|
||||
{"mip_display": 5} to increase the log verbosity.</dd>
|
||||
</dl></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class CplexPyomoSolver(BasePyomoSolver):
|
||||
"""
|
||||
An InternalSolver that uses CPLEX and the Pyomo modeling language.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
params: dict
|
||||
Dictionary of options to pass to the Pyomo solver. For example,
|
||||
{"mip_display": 5} to increase the log verbosity.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
params: Optional[SolverParams] = None,
|
||||
) -> None:
|
||||
if params is None:
|
||||
params = {}
|
||||
if "randomseed" not in params.keys():
|
||||
params["randomseed"] = randint(low=0, high=1000).rvs()
|
||||
if "mip_display" not in params.keys():
|
||||
params["mip_display"] = 4
|
||||
super().__init__(
|
||||
solver_factory=pe.SolverFactory("cplex_persistent"),
|
||||
params=params,
|
||||
)
|
||||
|
||||
def _get_warm_start_regexp(self):
|
||||
return "MIP start .* with objective ([0-9.e+-]*)\\."
|
||||
|
||||
def _get_node_count_regexp(self):
|
||||
return "^[ *] *([0-9]+)"</code></pre>
|
||||
</details>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li><a title="miplearn.solvers.pyomo.base.BasePyomoSolver" href="base.html#miplearn.solvers.pyomo.base.BasePyomoSolver">BasePyomoSolver</a></li>
|
||||
<li><a title="miplearn.solvers.internal.InternalSolver" href="../internal.html#miplearn.solvers.internal.InternalSolver">InternalSolver</a></li>
|
||||
<li>abc.ABC</li>
|
||||
</ul>
|
||||
<h3>Inherited members</h3>
|
||||
<ul class="hlist">
|
||||
<li><code><b><a title="miplearn.solvers.pyomo.base.BasePyomoSolver" href="base.html#miplearn.solvers.pyomo.base.BasePyomoSolver">BasePyomoSolver</a></b></code>:
|
||||
<ul class="hlist">
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.add_constraint" href="../internal.html#miplearn.solvers.internal.InternalSolver.add_constraint">add_constraint</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.extract_constraint" href="../internal.html#miplearn.solvers.internal.InternalSolver.extract_constraint">extract_constraint</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.fix" href="../internal.html#miplearn.solvers.internal.InternalSolver.fix">fix</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_constraint_ids" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_constraint_ids">get_constraint_ids</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_constraint_sense" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_constraint_sense">get_constraint_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_dual" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_dual">get_dual</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_empty_solution" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_empty_solution">get_empty_solution</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_inequality_slacks" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_inequality_slacks">get_inequality_slacks</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_sense" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_sense">get_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_solution" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_solution">get_solution</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_value" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_value">get_value</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.is_constraint_satisfied" href="../internal.html#miplearn.solvers.internal.InternalSolver.is_constraint_satisfied">is_constraint_satisfied</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.is_infeasible" href="../internal.html#miplearn.solvers.internal.InternalSolver.is_infeasible">is_infeasible</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.relax" href="../internal.html#miplearn.solvers.internal.InternalSolver.relax">relax</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.set_branching_priorities" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_branching_priorities">set_branching_priorities</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.set_constraint_sense" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_constraint_sense">set_constraint_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.set_instance" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_instance">set_instance</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.set_warm_start" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_warm_start">set_warm_start</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.solve" href="../internal.html#miplearn.solvers.internal.InternalSolver.solve">solve</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.solve_lp" href="../internal.html#miplearn.solvers.internal.InternalSolver.solve_lp">solve_lp</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="miplearn.solvers.pyomo" href="index.html">miplearn.solvers.pyomo</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="miplearn.solvers.pyomo.cplex.CplexPyomoSolver" href="#miplearn.solvers.pyomo.cplex.CplexPyomoSolver">CplexPyomoSolver</a></code></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.7.0</a>.</p>
|
||||
</footer>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad()</script>
|
||||
</body>
|
||||
</html>
|
||||
221
0.2/api/miplearn/solvers/pyomo/gurobi.html
Normal file
221
0.2/api/miplearn/solvers/pyomo/gurobi.html
Normal file
@@ -0,0 +1,221 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.7.0" />
|
||||
<title>miplearn.solvers.pyomo.gurobi API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
|
||||
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>miplearn.solvers.pyomo.gurobi</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from pyomo import environ as pe
|
||||
from scipy.stats import randint
|
||||
|
||||
from miplearn.solvers.pyomo.base import BasePyomoSolver
|
||||
from miplearn.types import SolverParams, BranchPriorities
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GurobiPyomoSolver(BasePyomoSolver):
|
||||
"""
|
||||
An InternalSolver that uses Gurobi and the Pyomo modeling language.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
params: dict
|
||||
Dictionary of options to pass to the Pyomo solver. For example,
|
||||
{"Threads": 4} to set the number of threads.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
params: SolverParams = None,
|
||||
) -> None:
|
||||
if params is None:
|
||||
params = {}
|
||||
if "seed" not in params.keys():
|
||||
params["seed"] = randint(low=0, high=1000).rvs()
|
||||
super().__init__(
|
||||
solver_factory=pe.SolverFactory("gurobi_persistent"),
|
||||
params=params,
|
||||
)
|
||||
|
||||
def _extract_node_count(self, log: str) -> int:
|
||||
return max(1, int(self._pyomo_solver._solver_model.getAttr("NodeCount")))
|
||||
|
||||
def _get_warm_start_regexp(self) -> str:
|
||||
return "MIP start with objective ([0-9.e+-]*)"
|
||||
|
||||
def _get_node_count_regexp(self) -> Optional[str]:
|
||||
return None
|
||||
|
||||
def set_branching_priorities(self, priorities: BranchPriorities) -> None:
|
||||
from gurobipy import GRB
|
||||
|
||||
for varname in priorities.keys():
|
||||
var = self._varname_to_var[varname]
|
||||
for (index, priority) in priorities[varname].items():
|
||||
if priority is None:
|
||||
continue
|
||||
gvar = self._pyomo_solver._pyomo_var_to_solver_var_map[var[index]]
|
||||
gvar.setAttr(GRB.Attr.BranchPriority, int(round(priority)))</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="miplearn.solvers.pyomo.gurobi.GurobiPyomoSolver"><code class="flex name class">
|
||||
<span>class <span class="ident">GurobiPyomoSolver</span></span>
|
||||
<span>(</span><span>params=None)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"><p>An InternalSolver that uses Gurobi and the Pyomo modeling language.</p>
|
||||
<h2 id="parameters">Parameters</h2>
|
||||
<dl>
|
||||
<dt><strong><code>params</code></strong> : <code>dict</code></dt>
|
||||
<dd>Dictionary of options to pass to the Pyomo solver. For example,
|
||||
{"Threads": 4} to set the number of threads.</dd>
|
||||
</dl></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class GurobiPyomoSolver(BasePyomoSolver):
|
||||
"""
|
||||
An InternalSolver that uses Gurobi and the Pyomo modeling language.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
params: dict
|
||||
Dictionary of options to pass to the Pyomo solver. For example,
|
||||
{"Threads": 4} to set the number of threads.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
params: SolverParams = None,
|
||||
) -> None:
|
||||
if params is None:
|
||||
params = {}
|
||||
if "seed" not in params.keys():
|
||||
params["seed"] = randint(low=0, high=1000).rvs()
|
||||
super().__init__(
|
||||
solver_factory=pe.SolverFactory("gurobi_persistent"),
|
||||
params=params,
|
||||
)
|
||||
|
||||
def _extract_node_count(self, log: str) -> int:
|
||||
return max(1, int(self._pyomo_solver._solver_model.getAttr("NodeCount")))
|
||||
|
||||
def _get_warm_start_regexp(self) -> str:
|
||||
return "MIP start with objective ([0-9.e+-]*)"
|
||||
|
||||
def _get_node_count_regexp(self) -> Optional[str]:
|
||||
return None
|
||||
|
||||
def set_branching_priorities(self, priorities: BranchPriorities) -> None:
|
||||
from gurobipy import GRB
|
||||
|
||||
for varname in priorities.keys():
|
||||
var = self._varname_to_var[varname]
|
||||
for (index, priority) in priorities[varname].items():
|
||||
if priority is None:
|
||||
continue
|
||||
gvar = self._pyomo_solver._pyomo_var_to_solver_var_map[var[index]]
|
||||
gvar.setAttr(GRB.Attr.BranchPriority, int(round(priority)))</code></pre>
|
||||
</details>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li><a title="miplearn.solvers.pyomo.base.BasePyomoSolver" href="base.html#miplearn.solvers.pyomo.base.BasePyomoSolver">BasePyomoSolver</a></li>
|
||||
<li><a title="miplearn.solvers.internal.InternalSolver" href="../internal.html#miplearn.solvers.internal.InternalSolver">InternalSolver</a></li>
|
||||
<li>abc.ABC</li>
|
||||
</ul>
|
||||
<h3>Inherited members</h3>
|
||||
<ul class="hlist">
|
||||
<li><code><b><a title="miplearn.solvers.pyomo.base.BasePyomoSolver" href="base.html#miplearn.solvers.pyomo.base.BasePyomoSolver">BasePyomoSolver</a></b></code>:
|
||||
<ul class="hlist">
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.add_constraint" href="../internal.html#miplearn.solvers.internal.InternalSolver.add_constraint">add_constraint</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.extract_constraint" href="../internal.html#miplearn.solvers.internal.InternalSolver.extract_constraint">extract_constraint</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.fix" href="../internal.html#miplearn.solvers.internal.InternalSolver.fix">fix</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_constraint_ids" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_constraint_ids">get_constraint_ids</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_constraint_sense" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_constraint_sense">get_constraint_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_dual" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_dual">get_dual</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_empty_solution" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_empty_solution">get_empty_solution</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_inequality_slacks" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_inequality_slacks">get_inequality_slacks</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_sense" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_sense">get_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_solution" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_solution">get_solution</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_value" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_value">get_value</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.is_constraint_satisfied" href="../internal.html#miplearn.solvers.internal.InternalSolver.is_constraint_satisfied">is_constraint_satisfied</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.is_infeasible" href="../internal.html#miplearn.solvers.internal.InternalSolver.is_infeasible">is_infeasible</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.relax" href="../internal.html#miplearn.solvers.internal.InternalSolver.relax">relax</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.set_branching_priorities" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_branching_priorities">set_branching_priorities</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.set_constraint_sense" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_constraint_sense">set_constraint_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.set_instance" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_instance">set_instance</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.set_warm_start" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_warm_start">set_warm_start</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.solve" href="../internal.html#miplearn.solvers.internal.InternalSolver.solve">solve</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.solve_lp" href="../internal.html#miplearn.solvers.internal.InternalSolver.solve_lp">solve_lp</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="miplearn.solvers.pyomo" href="index.html">miplearn.solvers.pyomo</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="miplearn.solvers.pyomo.gurobi.GurobiPyomoSolver" href="#miplearn.solvers.pyomo.gurobi.GurobiPyomoSolver">GurobiPyomoSolver</a></code></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.7.0</a>.</p>
|
||||
</footer>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad()</script>
|
||||
</body>
|
||||
</html>
|
||||
88
0.2/api/miplearn/solvers/pyomo/index.html
Normal file
88
0.2/api/miplearn/solvers/pyomo/index.html
Normal file
@@ -0,0 +1,88 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.7.0" />
|
||||
<title>miplearn.solvers.pyomo API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
|
||||
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>miplearn.solvers.pyomo</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-submodules">Sub-modules</h2>
|
||||
<dl>
|
||||
<dt><code class="name"><a title="miplearn.solvers.pyomo.base" href="base.html">miplearn.solvers.pyomo.base</a></code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="miplearn.solvers.pyomo.cplex" href="cplex.html">miplearn.solvers.pyomo.cplex</a></code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="miplearn.solvers.pyomo.gurobi" href="gurobi.html">miplearn.solvers.pyomo.gurobi</a></code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="miplearn.solvers.pyomo.xpress" href="xpress.html">miplearn.solvers.pyomo.xpress</a></code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="miplearn.solvers" href="../index.html">miplearn.solvers</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-submodules">Sub-modules</a></h3>
|
||||
<ul>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base" href="base.html">miplearn.solvers.pyomo.base</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.cplex" href="cplex.html">miplearn.solvers.pyomo.cplex</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.gurobi" href="gurobi.html">miplearn.solvers.pyomo.gurobi</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.xpress" href="xpress.html">miplearn.solvers.pyomo.xpress</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.7.0</a>.</p>
|
||||
</footer>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad()</script>
|
||||
</body>
|
||||
</html>
|
||||
174
0.2/api/miplearn/solvers/pyomo/xpress.html
Normal file
174
0.2/api/miplearn/solvers/pyomo/xpress.html
Normal file
@@ -0,0 +1,174 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.7.0" />
|
||||
<title>miplearn.solvers.pyomo.xpress API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
|
||||
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>miplearn.solvers.pyomo.xpress</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
import logging
|
||||
|
||||
from pyomo import environ as pe
|
||||
from scipy.stats import randint
|
||||
|
||||
from miplearn.solvers.pyomo.base import BasePyomoSolver
|
||||
from miplearn.types import SolverParams
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class XpressPyomoSolver(BasePyomoSolver):
|
||||
"""
|
||||
An InternalSolver that uses XPRESS and the Pyomo modeling language.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
params: dict
|
||||
Dictionary of options to pass to the Pyomo solver. For example,
|
||||
{"Threads": 4} to set the number of threads.
|
||||
"""
|
||||
|
||||
def __init__(self, params: SolverParams = None) -> None:
|
||||
if params is None:
|
||||
params = {}
|
||||
if "randomseed" not in params.keys():
|
||||
params["randomseed"] = randint(low=0, high=1000).rvs()
|
||||
super().__init__(
|
||||
solver_factory=pe.SolverFactory("xpress_persistent"),
|
||||
params=params,
|
||||
)</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="miplearn.solvers.pyomo.xpress.XpressPyomoSolver"><code class="flex name class">
|
||||
<span>class <span class="ident">XpressPyomoSolver</span></span>
|
||||
<span>(</span><span>params=None)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"><p>An InternalSolver that uses XPRESS and the Pyomo modeling language.</p>
|
||||
<h2 id="parameters">Parameters</h2>
|
||||
<dl>
|
||||
<dt><strong><code>params</code></strong> : <code>dict</code></dt>
|
||||
<dd>Dictionary of options to pass to the Pyomo solver. For example,
|
||||
{"Threads": 4} to set the number of threads.</dd>
|
||||
</dl></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class XpressPyomoSolver(BasePyomoSolver):
|
||||
"""
|
||||
An InternalSolver that uses XPRESS and the Pyomo modeling language.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
params: dict
|
||||
Dictionary of options to pass to the Pyomo solver. For example,
|
||||
{"Threads": 4} to set the number of threads.
|
||||
"""
|
||||
|
||||
def __init__(self, params: SolverParams = None) -> None:
|
||||
if params is None:
|
||||
params = {}
|
||||
if "randomseed" not in params.keys():
|
||||
params["randomseed"] = randint(low=0, high=1000).rvs()
|
||||
super().__init__(
|
||||
solver_factory=pe.SolverFactory("xpress_persistent"),
|
||||
params=params,
|
||||
)</code></pre>
|
||||
</details>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li><a title="miplearn.solvers.pyomo.base.BasePyomoSolver" href="base.html#miplearn.solvers.pyomo.base.BasePyomoSolver">BasePyomoSolver</a></li>
|
||||
<li><a title="miplearn.solvers.internal.InternalSolver" href="../internal.html#miplearn.solvers.internal.InternalSolver">InternalSolver</a></li>
|
||||
<li>abc.ABC</li>
|
||||
</ul>
|
||||
<h3>Inherited members</h3>
|
||||
<ul class="hlist">
|
||||
<li><code><b><a title="miplearn.solvers.pyomo.base.BasePyomoSolver" href="base.html#miplearn.solvers.pyomo.base.BasePyomoSolver">BasePyomoSolver</a></b></code>:
|
||||
<ul class="hlist">
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.add_constraint" href="../internal.html#miplearn.solvers.internal.InternalSolver.add_constraint">add_constraint</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.extract_constraint" href="../internal.html#miplearn.solvers.internal.InternalSolver.extract_constraint">extract_constraint</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.fix" href="../internal.html#miplearn.solvers.internal.InternalSolver.fix">fix</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_constraint_ids" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_constraint_ids">get_constraint_ids</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_constraint_sense" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_constraint_sense">get_constraint_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_dual" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_dual">get_dual</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_empty_solution" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_empty_solution">get_empty_solution</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_inequality_slacks" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_inequality_slacks">get_inequality_slacks</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_sense" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_sense">get_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_solution" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_solution">get_solution</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.get_value" href="../internal.html#miplearn.solvers.internal.InternalSolver.get_value">get_value</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.is_constraint_satisfied" href="../internal.html#miplearn.solvers.internal.InternalSolver.is_constraint_satisfied">is_constraint_satisfied</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.is_infeasible" href="../internal.html#miplearn.solvers.internal.InternalSolver.is_infeasible">is_infeasible</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.relax" href="../internal.html#miplearn.solvers.internal.InternalSolver.relax">relax</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.set_branching_priorities" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_branching_priorities">set_branching_priorities</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.set_constraint_sense" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_constraint_sense">set_constraint_sense</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.set_instance" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_instance">set_instance</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.set_warm_start" href="../internal.html#miplearn.solvers.internal.InternalSolver.set_warm_start">set_warm_start</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.solve" href="../internal.html#miplearn.solvers.internal.InternalSolver.solve">solve</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.pyomo.base.BasePyomoSolver.solve_lp" href="../internal.html#miplearn.solvers.internal.InternalSolver.solve_lp">solve_lp</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="miplearn.solvers.pyomo" href="index.html">miplearn.solvers.pyomo</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="miplearn.solvers.pyomo.xpress.XpressPyomoSolver" href="#miplearn.solvers.pyomo.xpress.XpressPyomoSolver">XpressPyomoSolver</a></code></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.7.0</a>.</p>
|
||||
</footer>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad()</script>
|
||||
</body>
|
||||
</html>
|
||||
250
0.2/api/miplearn/solvers/tests/index.html
Normal file
250
0.2/api/miplearn/solvers/tests/index.html
Normal file
@@ -0,0 +1,250 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.7.0" />
|
||||
<title>miplearn.solvers.tests API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
|
||||
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>miplearn.solvers.tests</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
from inspect import isclass
|
||||
from typing import List, Callable, Any
|
||||
|
||||
from pyomo import environ as pe
|
||||
|
||||
from miplearn.instance import Instance
|
||||
from miplearn.problems.knapsack import KnapsackInstance, GurobiKnapsackInstance
|
||||
from miplearn.solvers.gurobi import GurobiSolver
|
||||
from miplearn.solvers.internal import InternalSolver
|
||||
from miplearn.solvers.pyomo.base import BasePyomoSolver
|
||||
from miplearn.solvers.pyomo.gurobi import GurobiPyomoSolver
|
||||
from miplearn.solvers.pyomo.xpress import XpressPyomoSolver
|
||||
|
||||
|
||||
class InfeasiblePyomoInstance(Instance):
|
||||
def to_model(self) -> pe.ConcreteModel:
|
||||
model = pe.ConcreteModel()
|
||||
model.x = pe.Var([0], domain=pe.Binary)
|
||||
model.OBJ = pe.Objective(expr=model.x[0], sense=pe.maximize)
|
||||
model.eq = pe.Constraint(expr=model.x[0] >= 2)
|
||||
return model
|
||||
|
||||
|
||||
class InfeasibleGurobiInstance(Instance):
|
||||
def to_model(self) -> Any:
|
||||
import gurobipy as gp
|
||||
from gurobipy import GRB
|
||||
|
||||
model = gp.Model()
|
||||
x = model.addVars(1, vtype=GRB.BINARY, name="x")
|
||||
model.addConstr(x[0] >= 2)
|
||||
model.setObjective(x[0])
|
||||
return model
|
||||
|
||||
|
||||
def _is_subclass_or_instance(obj, parent_class):
|
||||
return isinstance(obj, parent_class) or (
|
||||
isclass(obj) and issubclass(obj, parent_class)
|
||||
)
|
||||
|
||||
|
||||
def _get_knapsack_instance(solver):
|
||||
if _is_subclass_or_instance(solver, BasePyomoSolver):
|
||||
return KnapsackInstance(
|
||||
weights=[23.0, 26.0, 20.0, 18.0],
|
||||
prices=[505.0, 352.0, 458.0, 220.0],
|
||||
capacity=67.0,
|
||||
)
|
||||
if _is_subclass_or_instance(solver, GurobiSolver):
|
||||
return GurobiKnapsackInstance(
|
||||
weights=[23.0, 26.0, 20.0, 18.0],
|
||||
prices=[505.0, 352.0, 458.0, 220.0],
|
||||
capacity=67.0,
|
||||
)
|
||||
assert False
|
||||
|
||||
|
||||
def _get_infeasible_instance(solver):
|
||||
if _is_subclass_or_instance(solver, BasePyomoSolver):
|
||||
return InfeasiblePyomoInstance()
|
||||
if _is_subclass_or_instance(solver, GurobiSolver):
|
||||
return InfeasibleGurobiInstance()
|
||||
|
||||
|
||||
def _get_internal_solvers() -> List[Callable[[], InternalSolver]]:
|
||||
return [GurobiPyomoSolver, GurobiSolver, XpressPyomoSolver]</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-submodules">Sub-modules</h2>
|
||||
<dl>
|
||||
<dt><code class="name"><a title="miplearn.solvers.tests.test_internal_solver" href="test_internal_solver.html">miplearn.solvers.tests.test_internal_solver</a></code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="miplearn.solvers.tests.test_lazy_cb" href="test_lazy_cb.html">miplearn.solvers.tests.test_lazy_cb</a></code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="miplearn.solvers.tests.test_learning_solver" href="test_learning_solver.html">miplearn.solvers.tests.test_learning_solver</a></code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="miplearn.solvers.tests.InfeasibleGurobiInstance"><code class="flex name class">
|
||||
<span>class <span class="ident">InfeasibleGurobiInstance</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"><p>Abstract class holding all the data necessary to generate a concrete model of the
|
||||
problem.</p>
|
||||
<p>In the knapsack problem, for example, this class could hold the number of items,
|
||||
their weights and costs, as well as the size of the knapsack. Objects
|
||||
implementing this class are able to convert themselves into a concrete
|
||||
optimization model, which can be optimized by a solver, or into arrays of
|
||||
features, which can be provided as inputs to machine learning models.</p></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class InfeasibleGurobiInstance(Instance):
|
||||
def to_model(self) -> Any:
|
||||
import gurobipy as gp
|
||||
from gurobipy import GRB
|
||||
|
||||
model = gp.Model()
|
||||
x = model.addVars(1, vtype=GRB.BINARY, name="x")
|
||||
model.addConstr(x[0] >= 2)
|
||||
model.setObjective(x[0])
|
||||
return model</code></pre>
|
||||
</details>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li><a title="miplearn.instance.Instance" href="../../instance.html#miplearn.instance.Instance">Instance</a></li>
|
||||
<li>abc.ABC</li>
|
||||
</ul>
|
||||
<h3>Inherited members</h3>
|
||||
<ul class="hlist">
|
||||
<li><code><b><a title="miplearn.instance.Instance" href="../../instance.html#miplearn.instance.Instance">Instance</a></b></code>:
|
||||
<ul class="hlist">
|
||||
<li><code><a title="miplearn.instance.Instance.build_lazy_constraint" href="../../instance.html#miplearn.instance.Instance.build_lazy_constraint">build_lazy_constraint</a></code></li>
|
||||
<li><code><a title="miplearn.instance.Instance.find_violated_lazy_constraints" href="../../instance.html#miplearn.instance.Instance.find_violated_lazy_constraints">find_violated_lazy_constraints</a></code></li>
|
||||
<li><code><a title="miplearn.instance.Instance.get_instance_features" href="../../instance.html#miplearn.instance.Instance.get_instance_features">get_instance_features</a></code></li>
|
||||
<li><code><a title="miplearn.instance.Instance.get_variable_category" href="../../instance.html#miplearn.instance.Instance.get_variable_category">get_variable_category</a></code></li>
|
||||
<li><code><a title="miplearn.instance.Instance.get_variable_features" href="../../instance.html#miplearn.instance.Instance.get_variable_features">get_variable_features</a></code></li>
|
||||
<li><code><a title="miplearn.instance.Instance.to_model" href="../../instance.html#miplearn.instance.Instance.to_model">to_model</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
<dt id="miplearn.solvers.tests.InfeasiblePyomoInstance"><code class="flex name class">
|
||||
<span>class <span class="ident">InfeasiblePyomoInstance</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"><p>Abstract class holding all the data necessary to generate a concrete model of the
|
||||
problem.</p>
|
||||
<p>In the knapsack problem, for example, this class could hold the number of items,
|
||||
their weights and costs, as well as the size of the knapsack. Objects
|
||||
implementing this class are able to convert themselves into a concrete
|
||||
optimization model, which can be optimized by a solver, or into arrays of
|
||||
features, which can be provided as inputs to machine learning models.</p></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class InfeasiblePyomoInstance(Instance):
|
||||
def to_model(self) -> pe.ConcreteModel:
|
||||
model = pe.ConcreteModel()
|
||||
model.x = pe.Var([0], domain=pe.Binary)
|
||||
model.OBJ = pe.Objective(expr=model.x[0], sense=pe.maximize)
|
||||
model.eq = pe.Constraint(expr=model.x[0] >= 2)
|
||||
return model</code></pre>
|
||||
</details>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li><a title="miplearn.instance.Instance" href="../../instance.html#miplearn.instance.Instance">Instance</a></li>
|
||||
<li>abc.ABC</li>
|
||||
</ul>
|
||||
<h3>Inherited members</h3>
|
||||
<ul class="hlist">
|
||||
<li><code><b><a title="miplearn.instance.Instance" href="../../instance.html#miplearn.instance.Instance">Instance</a></b></code>:
|
||||
<ul class="hlist">
|
||||
<li><code><a title="miplearn.instance.Instance.build_lazy_constraint" href="../../instance.html#miplearn.instance.Instance.build_lazy_constraint">build_lazy_constraint</a></code></li>
|
||||
<li><code><a title="miplearn.instance.Instance.find_violated_lazy_constraints" href="../../instance.html#miplearn.instance.Instance.find_violated_lazy_constraints">find_violated_lazy_constraints</a></code></li>
|
||||
<li><code><a title="miplearn.instance.Instance.get_instance_features" href="../../instance.html#miplearn.instance.Instance.get_instance_features">get_instance_features</a></code></li>
|
||||
<li><code><a title="miplearn.instance.Instance.get_variable_category" href="../../instance.html#miplearn.instance.Instance.get_variable_category">get_variable_category</a></code></li>
|
||||
<li><code><a title="miplearn.instance.Instance.get_variable_features" href="../../instance.html#miplearn.instance.Instance.get_variable_features">get_variable_features</a></code></li>
|
||||
<li><code><a title="miplearn.instance.Instance.to_model" href="../../instance.html#miplearn.instance.Instance.to_model">to_model</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="miplearn.solvers" href="../index.html">miplearn.solvers</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-submodules">Sub-modules</a></h3>
|
||||
<ul>
|
||||
<li><code><a title="miplearn.solvers.tests.test_internal_solver" href="test_internal_solver.html">miplearn.solvers.tests.test_internal_solver</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.tests.test_lazy_cb" href="test_lazy_cb.html">miplearn.solvers.tests.test_lazy_cb</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.tests.test_learning_solver" href="test_learning_solver.html">miplearn.solvers.tests.test_learning_solver</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="miplearn.solvers.tests.InfeasibleGurobiInstance" href="#miplearn.solvers.tests.InfeasibleGurobiInstance">InfeasibleGurobiInstance</a></code></h4>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="miplearn.solvers.tests.InfeasiblePyomoInstance" href="#miplearn.solvers.tests.InfeasiblePyomoInstance">InfeasiblePyomoInstance</a></code></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.7.0</a>.</p>
|
||||
</footer>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad()</script>
|
||||
</body>
|
||||
</html>
|
||||
543
0.2/api/miplearn/solvers/tests/test_internal_solver.html
Normal file
543
0.2/api/miplearn/solvers/tests/test_internal_solver.html
Normal file
@@ -0,0 +1,543 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.7.0" />
|
||||
<title>miplearn.solvers.tests.test_internal_solver API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
|
||||
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>miplearn.solvers.tests.test_internal_solver</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
import logging
|
||||
from io import StringIO
|
||||
from warnings import warn
|
||||
|
||||
import pyomo.environ as pe
|
||||
|
||||
from miplearn.solvers import _RedirectOutput
|
||||
from miplearn.solvers.gurobi import GurobiSolver
|
||||
from miplearn.solvers.pyomo.base import BasePyomoSolver
|
||||
from miplearn.solvers.tests import (
|
||||
_get_knapsack_instance,
|
||||
_get_internal_solvers,
|
||||
_get_infeasible_instance,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def test_redirect_output():
|
||||
import sys
|
||||
|
||||
original_stdout = sys.stdout
|
||||
io = StringIO()
|
||||
with _RedirectOutput([io]):
|
||||
print("Hello world")
|
||||
assert sys.stdout == original_stdout
|
||||
assert io.getvalue() == "Hello world\n"
|
||||
|
||||
|
||||
def test_internal_solver_warm_starts():
|
||||
for solver_class in _get_internal_solvers():
|
||||
logger.info("Solver: %s" % solver_class)
|
||||
instance = _get_knapsack_instance(solver_class)
|
||||
model = instance.to_model()
|
||||
solver = solver_class()
|
||||
solver.set_instance(instance, model)
|
||||
solver.set_warm_start(
|
||||
{
|
||||
"x": {
|
||||
0: 1.0,
|
||||
1: 0.0,
|
||||
2: 0.0,
|
||||
3: 1.0,
|
||||
}
|
||||
}
|
||||
)
|
||||
stats = solver.solve(tee=True)
|
||||
if stats["Warm start value"] is not None:
|
||||
assert stats["Warm start value"] == 725.0
|
||||
else:
|
||||
warn(f"{solver_class.__name__} should set warm start value")
|
||||
|
||||
solver.set_warm_start(
|
||||
{
|
||||
"x": {
|
||||
0: 1.0,
|
||||
1: 1.0,
|
||||
2: 1.0,
|
||||
3: 1.0,
|
||||
}
|
||||
}
|
||||
)
|
||||
stats = solver.solve(tee=True)
|
||||
assert stats["Warm start value"] is None
|
||||
|
||||
solver.fix(
|
||||
{
|
||||
"x": {
|
||||
0: 1.0,
|
||||
1: 0.0,
|
||||
2: 0.0,
|
||||
3: 1.0,
|
||||
}
|
||||
}
|
||||
)
|
||||
stats = solver.solve(tee=True)
|
||||
assert stats["Lower bound"] == 725.0
|
||||
assert stats["Upper bound"] == 725.0
|
||||
|
||||
|
||||
def test_internal_solver():
|
||||
for solver_class in _get_internal_solvers():
|
||||
logger.info("Solver: %s" % solver_class)
|
||||
|
||||
instance = _get_knapsack_instance(solver_class)
|
||||
model = instance.to_model()
|
||||
solver = solver_class()
|
||||
solver.set_instance(instance, model)
|
||||
|
||||
stats = solver.solve_lp()
|
||||
assert not solver.is_infeasible()
|
||||
assert round(stats["Optimal value"], 3) == 1287.923
|
||||
assert len(stats["Log"]) > 100
|
||||
|
||||
solution = solver.get_solution()
|
||||
assert round(solution["x"][0], 3) == 1.000
|
||||
assert round(solution["x"][1], 3) == 0.923
|
||||
assert round(solution["x"][2], 3) == 1.000
|
||||
assert round(solution["x"][3], 3) == 0.000
|
||||
|
||||
stats = solver.solve(tee=True)
|
||||
assert not solver.is_infeasible()
|
||||
assert len(stats["Log"]) > 100
|
||||
assert stats["Lower bound"] == 1183.0
|
||||
assert stats["Upper bound"] == 1183.0
|
||||
assert stats["Sense"] == "max"
|
||||
assert isinstance(stats["Wallclock time"], float)
|
||||
|
||||
solution = solver.get_solution()
|
||||
assert solution["x"][0] == 1.0
|
||||
assert solution["x"][1] == 0.0
|
||||
assert solution["x"][2] == 1.0
|
||||
assert solution["x"][3] == 1.0
|
||||
|
||||
# Add a brand new constraint
|
||||
if isinstance(solver, BasePyomoSolver):
|
||||
model.cut = pe.Constraint(expr=model.x[0] <= 0.0, name="cut")
|
||||
solver.add_constraint(model.cut)
|
||||
elif isinstance(solver, GurobiSolver):
|
||||
x = model.getVarByName("x[0]")
|
||||
solver.add_constraint(x <= 0.0, name="cut")
|
||||
else:
|
||||
raise Exception("Illegal state")
|
||||
|
||||
# New constraint should affect solution and should be listed in
|
||||
# constraint ids
|
||||
assert solver.get_constraint_ids() == ["eq_capacity", "cut"]
|
||||
stats = solver.solve()
|
||||
assert stats["Lower bound"] == 1030.0
|
||||
|
||||
assert solver.get_sense() == "max"
|
||||
assert solver.get_constraint_sense("cut") == "<"
|
||||
assert solver.get_constraint_sense("eq_capacity") == "<"
|
||||
|
||||
# Verify slacks
|
||||
assert solver.get_inequality_slacks() == {
|
||||
"cut": 0.0,
|
||||
"eq_capacity": 3.0,
|
||||
}
|
||||
|
||||
if isinstance(solver, GurobiSolver):
|
||||
# Extract the new constraint
|
||||
cobj = solver.extract_constraint("cut")
|
||||
|
||||
# New constraint should no longer affect solution and should no longer
|
||||
# be listed in constraint ids
|
||||
assert solver.get_constraint_ids() == ["eq_capacity"]
|
||||
stats = solver.solve()
|
||||
assert stats["Lower bound"] == 1183.0
|
||||
|
||||
# New constraint should not be satisfied by current solution
|
||||
assert not solver.is_constraint_satisfied(cobj)
|
||||
|
||||
# Re-add constraint
|
||||
solver.add_constraint(cobj)
|
||||
|
||||
# Constraint should affect solution again
|
||||
assert solver.get_constraint_ids() == ["eq_capacity", "cut"]
|
||||
stats = solver.solve()
|
||||
assert stats["Lower bound"] == 1030.0
|
||||
|
||||
# New constraint should now be satisfied
|
||||
assert solver.is_constraint_satisfied(cobj)
|
||||
|
||||
# Relax problem and make cut into an equality constraint
|
||||
solver.relax()
|
||||
solver.set_constraint_sense("cut", "=")
|
||||
stats = solver.solve()
|
||||
assert round(stats["Lower bound"]) == 1030.0
|
||||
assert round(solver.get_dual("eq_capacity")) == 0.0
|
||||
|
||||
|
||||
def test_relax():
|
||||
for solver_class in _get_internal_solvers():
|
||||
instance = _get_knapsack_instance(solver_class)
|
||||
solver = solver_class()
|
||||
solver.set_instance(instance)
|
||||
solver.relax()
|
||||
stats = solver.solve()
|
||||
assert round(stats["Lower bound"]) == 1288.0
|
||||
|
||||
|
||||
def test_infeasible_instance():
|
||||
for solver_class in _get_internal_solvers():
|
||||
instance = _get_infeasible_instance(solver_class)
|
||||
solver = solver_class()
|
||||
solver.set_instance(instance)
|
||||
stats = solver.solve()
|
||||
|
||||
assert solver.is_infeasible()
|
||||
assert solver.get_solution() is None
|
||||
assert stats["Upper bound"] is None
|
||||
assert stats["Lower bound"] is None
|
||||
|
||||
stats = solver.solve_lp()
|
||||
assert solver.get_solution() is None
|
||||
assert stats["Optimal value"] is None
|
||||
assert solver.get_value("x", 0) is None
|
||||
|
||||
|
||||
def test_iteration_cb():
|
||||
for solver_class in _get_internal_solvers():
|
||||
logger.info("Solver: %s" % solver_class)
|
||||
instance = _get_knapsack_instance(solver_class)
|
||||
solver = solver_class()
|
||||
solver.set_instance(instance)
|
||||
count = 0
|
||||
|
||||
def custom_iteration_cb():
|
||||
nonlocal count
|
||||
count += 1
|
||||
return count < 5
|
||||
|
||||
solver.solve(iteration_cb=custom_iteration_cb)
|
||||
assert count == 5</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="miplearn.solvers.tests.test_internal_solver.test_infeasible_instance"><code class="name flex">
|
||||
<span>def <span class="ident">test_infeasible_instance</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_infeasible_instance():
|
||||
for solver_class in _get_internal_solvers():
|
||||
instance = _get_infeasible_instance(solver_class)
|
||||
solver = solver_class()
|
||||
solver.set_instance(instance)
|
||||
stats = solver.solve()
|
||||
|
||||
assert solver.is_infeasible()
|
||||
assert solver.get_solution() is None
|
||||
assert stats["Upper bound"] is None
|
||||
assert stats["Lower bound"] is None
|
||||
|
||||
stats = solver.solve_lp()
|
||||
assert solver.get_solution() is None
|
||||
assert stats["Optimal value"] is None
|
||||
assert solver.get_value("x", 0) is None</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="miplearn.solvers.tests.test_internal_solver.test_internal_solver"><code class="name flex">
|
||||
<span>def <span class="ident">test_internal_solver</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_internal_solver():
|
||||
for solver_class in _get_internal_solvers():
|
||||
logger.info("Solver: %s" % solver_class)
|
||||
|
||||
instance = _get_knapsack_instance(solver_class)
|
||||
model = instance.to_model()
|
||||
solver = solver_class()
|
||||
solver.set_instance(instance, model)
|
||||
|
||||
stats = solver.solve_lp()
|
||||
assert not solver.is_infeasible()
|
||||
assert round(stats["Optimal value"], 3) == 1287.923
|
||||
assert len(stats["Log"]) > 100
|
||||
|
||||
solution = solver.get_solution()
|
||||
assert round(solution["x"][0], 3) == 1.000
|
||||
assert round(solution["x"][1], 3) == 0.923
|
||||
assert round(solution["x"][2], 3) == 1.000
|
||||
assert round(solution["x"][3], 3) == 0.000
|
||||
|
||||
stats = solver.solve(tee=True)
|
||||
assert not solver.is_infeasible()
|
||||
assert len(stats["Log"]) > 100
|
||||
assert stats["Lower bound"] == 1183.0
|
||||
assert stats["Upper bound"] == 1183.0
|
||||
assert stats["Sense"] == "max"
|
||||
assert isinstance(stats["Wallclock time"], float)
|
||||
|
||||
solution = solver.get_solution()
|
||||
assert solution["x"][0] == 1.0
|
||||
assert solution["x"][1] == 0.0
|
||||
assert solution["x"][2] == 1.0
|
||||
assert solution["x"][3] == 1.0
|
||||
|
||||
# Add a brand new constraint
|
||||
if isinstance(solver, BasePyomoSolver):
|
||||
model.cut = pe.Constraint(expr=model.x[0] <= 0.0, name="cut")
|
||||
solver.add_constraint(model.cut)
|
||||
elif isinstance(solver, GurobiSolver):
|
||||
x = model.getVarByName("x[0]")
|
||||
solver.add_constraint(x <= 0.0, name="cut")
|
||||
else:
|
||||
raise Exception("Illegal state")
|
||||
|
||||
# New constraint should affect solution and should be listed in
|
||||
# constraint ids
|
||||
assert solver.get_constraint_ids() == ["eq_capacity", "cut"]
|
||||
stats = solver.solve()
|
||||
assert stats["Lower bound"] == 1030.0
|
||||
|
||||
assert solver.get_sense() == "max"
|
||||
assert solver.get_constraint_sense("cut") == "<"
|
||||
assert solver.get_constraint_sense("eq_capacity") == "<"
|
||||
|
||||
# Verify slacks
|
||||
assert solver.get_inequality_slacks() == {
|
||||
"cut": 0.0,
|
||||
"eq_capacity": 3.0,
|
||||
}
|
||||
|
||||
if isinstance(solver, GurobiSolver):
|
||||
# Extract the new constraint
|
||||
cobj = solver.extract_constraint("cut")
|
||||
|
||||
# New constraint should no longer affect solution and should no longer
|
||||
# be listed in constraint ids
|
||||
assert solver.get_constraint_ids() == ["eq_capacity"]
|
||||
stats = solver.solve()
|
||||
assert stats["Lower bound"] == 1183.0
|
||||
|
||||
# New constraint should not be satisfied by current solution
|
||||
assert not solver.is_constraint_satisfied(cobj)
|
||||
|
||||
# Re-add constraint
|
||||
solver.add_constraint(cobj)
|
||||
|
||||
# Constraint should affect solution again
|
||||
assert solver.get_constraint_ids() == ["eq_capacity", "cut"]
|
||||
stats = solver.solve()
|
||||
assert stats["Lower bound"] == 1030.0
|
||||
|
||||
# New constraint should now be satisfied
|
||||
assert solver.is_constraint_satisfied(cobj)
|
||||
|
||||
# Relax problem and make cut into an equality constraint
|
||||
solver.relax()
|
||||
solver.set_constraint_sense("cut", "=")
|
||||
stats = solver.solve()
|
||||
assert round(stats["Lower bound"]) == 1030.0
|
||||
assert round(solver.get_dual("eq_capacity")) == 0.0</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="miplearn.solvers.tests.test_internal_solver.test_internal_solver_warm_starts"><code class="name flex">
|
||||
<span>def <span class="ident">test_internal_solver_warm_starts</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_internal_solver_warm_starts():
|
||||
for solver_class in _get_internal_solvers():
|
||||
logger.info("Solver: %s" % solver_class)
|
||||
instance = _get_knapsack_instance(solver_class)
|
||||
model = instance.to_model()
|
||||
solver = solver_class()
|
||||
solver.set_instance(instance, model)
|
||||
solver.set_warm_start(
|
||||
{
|
||||
"x": {
|
||||
0: 1.0,
|
||||
1: 0.0,
|
||||
2: 0.0,
|
||||
3: 1.0,
|
||||
}
|
||||
}
|
||||
)
|
||||
stats = solver.solve(tee=True)
|
||||
if stats["Warm start value"] is not None:
|
||||
assert stats["Warm start value"] == 725.0
|
||||
else:
|
||||
warn(f"{solver_class.__name__} should set warm start value")
|
||||
|
||||
solver.set_warm_start(
|
||||
{
|
||||
"x": {
|
||||
0: 1.0,
|
||||
1: 1.0,
|
||||
2: 1.0,
|
||||
3: 1.0,
|
||||
}
|
||||
}
|
||||
)
|
||||
stats = solver.solve(tee=True)
|
||||
assert stats["Warm start value"] is None
|
||||
|
||||
solver.fix(
|
||||
{
|
||||
"x": {
|
||||
0: 1.0,
|
||||
1: 0.0,
|
||||
2: 0.0,
|
||||
3: 1.0,
|
||||
}
|
||||
}
|
||||
)
|
||||
stats = solver.solve(tee=True)
|
||||
assert stats["Lower bound"] == 725.0
|
||||
assert stats["Upper bound"] == 725.0</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="miplearn.solvers.tests.test_internal_solver.test_iteration_cb"><code class="name flex">
|
||||
<span>def <span class="ident">test_iteration_cb</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_iteration_cb():
|
||||
for solver_class in _get_internal_solvers():
|
||||
logger.info("Solver: %s" % solver_class)
|
||||
instance = _get_knapsack_instance(solver_class)
|
||||
solver = solver_class()
|
||||
solver.set_instance(instance)
|
||||
count = 0
|
||||
|
||||
def custom_iteration_cb():
|
||||
nonlocal count
|
||||
count += 1
|
||||
return count < 5
|
||||
|
||||
solver.solve(iteration_cb=custom_iteration_cb)
|
||||
assert count == 5</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="miplearn.solvers.tests.test_internal_solver.test_redirect_output"><code class="name flex">
|
||||
<span>def <span class="ident">test_redirect_output</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_redirect_output():
|
||||
import sys
|
||||
|
||||
original_stdout = sys.stdout
|
||||
io = StringIO()
|
||||
with _RedirectOutput([io]):
|
||||
print("Hello world")
|
||||
assert sys.stdout == original_stdout
|
||||
assert io.getvalue() == "Hello world\n"</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="miplearn.solvers.tests.test_internal_solver.test_relax"><code class="name flex">
|
||||
<span>def <span class="ident">test_relax</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_relax():
|
||||
for solver_class in _get_internal_solvers():
|
||||
instance = _get_knapsack_instance(solver_class)
|
||||
solver = solver_class()
|
||||
solver.set_instance(instance)
|
||||
solver.relax()
|
||||
stats = solver.solve()
|
||||
assert round(stats["Lower bound"]) == 1288.0</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="miplearn.solvers.tests" href="index.html">miplearn.solvers.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="miplearn.solvers.tests.test_internal_solver.test_infeasible_instance" href="#miplearn.solvers.tests.test_internal_solver.test_infeasible_instance">test_infeasible_instance</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.tests.test_internal_solver.test_internal_solver" href="#miplearn.solvers.tests.test_internal_solver.test_internal_solver">test_internal_solver</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.tests.test_internal_solver.test_internal_solver_warm_starts" href="#miplearn.solvers.tests.test_internal_solver.test_internal_solver_warm_starts">test_internal_solver_warm_starts</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.tests.test_internal_solver.test_iteration_cb" href="#miplearn.solvers.tests.test_internal_solver.test_iteration_cb">test_iteration_cb</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.tests.test_internal_solver.test_redirect_output" href="#miplearn.solvers.tests.test_internal_solver.test_redirect_output">test_redirect_output</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.tests.test_internal_solver.test_relax" href="#miplearn.solvers.tests.test_internal_solver.test_relax">test_relax</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.7.0</a>.</p>
|
||||
</footer>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad()</script>
|
||||
</body>
|
||||
</html>
|
||||
119
0.2/api/miplearn/solvers/tests/test_lazy_cb.html
Normal file
119
0.2/api/miplearn/solvers/tests/test_lazy_cb.html
Normal file
@@ -0,0 +1,119 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.7.0" />
|
||||
<title>miplearn.solvers.tests.test_lazy_cb API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
|
||||
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>miplearn.solvers.tests.test_lazy_cb</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
import logging
|
||||
|
||||
from miplearn.solvers.gurobi import GurobiSolver
|
||||
from miplearn.solvers.tests import _get_knapsack_instance
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def test_lazy_cb():
|
||||
solver = GurobiSolver()
|
||||
instance = _get_knapsack_instance(solver)
|
||||
model = instance.to_model()
|
||||
|
||||
def lazy_cb(cb_solver, cb_model):
|
||||
logger.info("x[0] = %.f" % cb_solver.get_value("x", 0))
|
||||
cobj = (cb_model.getVarByName("x[0]") * 1.0, "<", 0.0, "cut")
|
||||
if not cb_solver.is_constraint_satisfied(cobj):
|
||||
cb_solver.add_constraint(cobj)
|
||||
|
||||
solver.set_instance(instance, model)
|
||||
solver.solve(lazy_cb=lazy_cb)
|
||||
solution = solver.get_solution()
|
||||
assert solution["x"][0] == 0.0</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="miplearn.solvers.tests.test_lazy_cb.test_lazy_cb"><code class="name flex">
|
||||
<span>def <span class="ident">test_lazy_cb</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_lazy_cb():
|
||||
solver = GurobiSolver()
|
||||
instance = _get_knapsack_instance(solver)
|
||||
model = instance.to_model()
|
||||
|
||||
def lazy_cb(cb_solver, cb_model):
|
||||
logger.info("x[0] = %.f" % cb_solver.get_value("x", 0))
|
||||
cobj = (cb_model.getVarByName("x[0]") * 1.0, "<", 0.0, "cut")
|
||||
if not cb_solver.is_constraint_satisfied(cobj):
|
||||
cb_solver.add_constraint(cobj)
|
||||
|
||||
solver.set_instance(instance, model)
|
||||
solver.solve(lazy_cb=lazy_cb)
|
||||
solution = solver.get_solution()
|
||||
assert solution["x"][0] == 0.0</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="miplearn.solvers.tests" href="index.html">miplearn.solvers.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="miplearn.solvers.tests.test_lazy_cb.test_lazy_cb" href="#miplearn.solvers.tests.test_lazy_cb.test_lazy_cb">test_lazy_cb</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.7.0</a>.</p>
|
||||
</footer>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad()</script>
|
||||
</body>
|
||||
</html>
|
||||
365
0.2/api/miplearn/solvers/tests/test_learning_solver.html
Normal file
365
0.2/api/miplearn/solvers/tests/test_learning_solver.html
Normal file
@@ -0,0 +1,365 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.7.0" />
|
||||
<title>miplearn.solvers.tests.test_learning_solver API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
|
||||
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
|
||||
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>miplearn.solvers.tests.test_learning_solver</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
import logging
|
||||
import pickle
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
from miplearn.solvers.gurobi import GurobiSolver
|
||||
from miplearn.solvers.learning import LearningSolver
|
||||
from miplearn.solvers.tests import _get_knapsack_instance, _get_internal_solvers
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def test_learning_solver():
|
||||
for mode in ["exact", "heuristic"]:
|
||||
for internal_solver in _get_internal_solvers():
|
||||
logger.info("Solver: %s" % internal_solver)
|
||||
instance = _get_knapsack_instance(internal_solver)
|
||||
solver = LearningSolver(
|
||||
solver=internal_solver,
|
||||
mode=mode,
|
||||
)
|
||||
|
||||
solver.solve(instance)
|
||||
data = instance.training_data[0]
|
||||
assert data["Solution"]["x"][0] == 1.0
|
||||
assert data["Solution"]["x"][1] == 0.0
|
||||
assert data["Solution"]["x"][2] == 1.0
|
||||
assert data["Solution"]["x"][3] == 1.0
|
||||
assert data["Lower bound"] == 1183.0
|
||||
assert data["Upper bound"] == 1183.0
|
||||
assert round(data["LP solution"]["x"][0], 3) == 1.000
|
||||
assert round(data["LP solution"]["x"][1], 3) == 0.923
|
||||
assert round(data["LP solution"]["x"][2], 3) == 1.000
|
||||
assert round(data["LP solution"]["x"][3], 3) == 0.000
|
||||
assert round(data["LP value"], 3) == 1287.923
|
||||
assert len(data["MIP log"]) > 100
|
||||
|
||||
solver.fit([instance])
|
||||
solver.solve(instance)
|
||||
|
||||
# Assert solver is picklable
|
||||
with tempfile.TemporaryFile() as file:
|
||||
pickle.dump(solver, file)
|
||||
|
||||
|
||||
def test_solve_without_lp():
|
||||
for internal_solver in _get_internal_solvers():
|
||||
logger.info("Solver: %s" % internal_solver)
|
||||
instance = _get_knapsack_instance(internal_solver)
|
||||
solver = LearningSolver(
|
||||
solver=internal_solver,
|
||||
solve_lp_first=False,
|
||||
)
|
||||
solver.solve(instance)
|
||||
solver.fit([instance])
|
||||
solver.solve(instance)
|
||||
|
||||
|
||||
def test_parallel_solve():
|
||||
for internal_solver in _get_internal_solvers():
|
||||
instances = [_get_knapsack_instance(internal_solver) for _ in range(10)]
|
||||
solver = LearningSolver(solver=internal_solver)
|
||||
results = solver.parallel_solve(instances, n_jobs=3)
|
||||
assert len(results) == 10
|
||||
for instance in instances:
|
||||
data = instance.training_data[0]
|
||||
assert len(data["Solution"]["x"].keys()) == 4
|
||||
|
||||
|
||||
def test_solve_fit_from_disk():
|
||||
for internal_solver in _get_internal_solvers():
|
||||
# Create instances and pickle them
|
||||
filenames = []
|
||||
for k in range(3):
|
||||
instance = _get_knapsack_instance(internal_solver)
|
||||
with tempfile.NamedTemporaryFile(suffix=".pkl", delete=False) as file:
|
||||
filenames += [file.name]
|
||||
pickle.dump(instance, file)
|
||||
|
||||
# Test: solve
|
||||
solver = LearningSolver(solver=internal_solver)
|
||||
solver.solve(filenames[0])
|
||||
with open(filenames[0], "rb") as file:
|
||||
instance = pickle.load(file)
|
||||
assert len(instance.training_data) > 0
|
||||
|
||||
# Test: parallel_solve
|
||||
solver.parallel_solve(filenames)
|
||||
for filename in filenames:
|
||||
with open(filename, "rb") as file:
|
||||
instance = pickle.load(file)
|
||||
assert len(instance.training_data) > 0
|
||||
|
||||
# Test: solve (with specified output)
|
||||
output = [f + ".out" for f in filenames]
|
||||
solver.solve(
|
||||
filenames[0],
|
||||
output_filename=output[0],
|
||||
)
|
||||
assert os.path.isfile(output[0])
|
||||
|
||||
# Test: parallel_solve (with specified output)
|
||||
solver.parallel_solve(
|
||||
filenames,
|
||||
output_filenames=output,
|
||||
)
|
||||
for filename in output:
|
||||
assert os.path.isfile(filename)
|
||||
|
||||
# Delete temporary files
|
||||
for filename in filenames:
|
||||
os.remove(filename)
|
||||
for filename in output:
|
||||
os.remove(filename)
|
||||
|
||||
|
||||
def test_simulate_perfect():
|
||||
internal_solver = GurobiSolver
|
||||
instance = _get_knapsack_instance(internal_solver)
|
||||
with tempfile.NamedTemporaryFile(suffix=".pkl", delete=False) as tmp:
|
||||
pickle.dump(instance, tmp)
|
||||
tmp.flush()
|
||||
solver = LearningSolver(
|
||||
solver=internal_solver,
|
||||
simulate_perfect=True,
|
||||
)
|
||||
stats = solver.solve(tmp.name)
|
||||
assert stats["Lower bound"] == stats["Predicted LB"]</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="miplearn.solvers.tests.test_learning_solver.test_learning_solver"><code class="name flex">
|
||||
<span>def <span class="ident">test_learning_solver</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_learning_solver():
|
||||
for mode in ["exact", "heuristic"]:
|
||||
for internal_solver in _get_internal_solvers():
|
||||
logger.info("Solver: %s" % internal_solver)
|
||||
instance = _get_knapsack_instance(internal_solver)
|
||||
solver = LearningSolver(
|
||||
solver=internal_solver,
|
||||
mode=mode,
|
||||
)
|
||||
|
||||
solver.solve(instance)
|
||||
data = instance.training_data[0]
|
||||
assert data["Solution"]["x"][0] == 1.0
|
||||
assert data["Solution"]["x"][1] == 0.0
|
||||
assert data["Solution"]["x"][2] == 1.0
|
||||
assert data["Solution"]["x"][3] == 1.0
|
||||
assert data["Lower bound"] == 1183.0
|
||||
assert data["Upper bound"] == 1183.0
|
||||
assert round(data["LP solution"]["x"][0], 3) == 1.000
|
||||
assert round(data["LP solution"]["x"][1], 3) == 0.923
|
||||
assert round(data["LP solution"]["x"][2], 3) == 1.000
|
||||
assert round(data["LP solution"]["x"][3], 3) == 0.000
|
||||
assert round(data["LP value"], 3) == 1287.923
|
||||
assert len(data["MIP log"]) > 100
|
||||
|
||||
solver.fit([instance])
|
||||
solver.solve(instance)
|
||||
|
||||
# Assert solver is picklable
|
||||
with tempfile.TemporaryFile() as file:
|
||||
pickle.dump(solver, file)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="miplearn.solvers.tests.test_learning_solver.test_parallel_solve"><code class="name flex">
|
||||
<span>def <span class="ident">test_parallel_solve</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_parallel_solve():
|
||||
for internal_solver in _get_internal_solvers():
|
||||
instances = [_get_knapsack_instance(internal_solver) for _ in range(10)]
|
||||
solver = LearningSolver(solver=internal_solver)
|
||||
results = solver.parallel_solve(instances, n_jobs=3)
|
||||
assert len(results) == 10
|
||||
for instance in instances:
|
||||
data = instance.training_data[0]
|
||||
assert len(data["Solution"]["x"].keys()) == 4</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="miplearn.solvers.tests.test_learning_solver.test_simulate_perfect"><code class="name flex">
|
||||
<span>def <span class="ident">test_simulate_perfect</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_simulate_perfect():
|
||||
internal_solver = GurobiSolver
|
||||
instance = _get_knapsack_instance(internal_solver)
|
||||
with tempfile.NamedTemporaryFile(suffix=".pkl", delete=False) as tmp:
|
||||
pickle.dump(instance, tmp)
|
||||
tmp.flush()
|
||||
solver = LearningSolver(
|
||||
solver=internal_solver,
|
||||
simulate_perfect=True,
|
||||
)
|
||||
stats = solver.solve(tmp.name)
|
||||
assert stats["Lower bound"] == stats["Predicted LB"]</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="miplearn.solvers.tests.test_learning_solver.test_solve_fit_from_disk"><code class="name flex">
|
||||
<span>def <span class="ident">test_solve_fit_from_disk</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_solve_fit_from_disk():
|
||||
for internal_solver in _get_internal_solvers():
|
||||
# Create instances and pickle them
|
||||
filenames = []
|
||||
for k in range(3):
|
||||
instance = _get_knapsack_instance(internal_solver)
|
||||
with tempfile.NamedTemporaryFile(suffix=".pkl", delete=False) as file:
|
||||
filenames += [file.name]
|
||||
pickle.dump(instance, file)
|
||||
|
||||
# Test: solve
|
||||
solver = LearningSolver(solver=internal_solver)
|
||||
solver.solve(filenames[0])
|
||||
with open(filenames[0], "rb") as file:
|
||||
instance = pickle.load(file)
|
||||
assert len(instance.training_data) > 0
|
||||
|
||||
# Test: parallel_solve
|
||||
solver.parallel_solve(filenames)
|
||||
for filename in filenames:
|
||||
with open(filename, "rb") as file:
|
||||
instance = pickle.load(file)
|
||||
assert len(instance.training_data) > 0
|
||||
|
||||
# Test: solve (with specified output)
|
||||
output = [f + ".out" for f in filenames]
|
||||
solver.solve(
|
||||
filenames[0],
|
||||
output_filename=output[0],
|
||||
)
|
||||
assert os.path.isfile(output[0])
|
||||
|
||||
# Test: parallel_solve (with specified output)
|
||||
solver.parallel_solve(
|
||||
filenames,
|
||||
output_filenames=output,
|
||||
)
|
||||
for filename in output:
|
||||
assert os.path.isfile(filename)
|
||||
|
||||
# Delete temporary files
|
||||
for filename in filenames:
|
||||
os.remove(filename)
|
||||
for filename in output:
|
||||
os.remove(filename)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="miplearn.solvers.tests.test_learning_solver.test_solve_without_lp"><code class="name flex">
|
||||
<span>def <span class="ident">test_solve_without_lp</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<section class="desc"></section>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_solve_without_lp():
|
||||
for internal_solver in _get_internal_solvers():
|
||||
logger.info("Solver: %s" % internal_solver)
|
||||
instance = _get_knapsack_instance(internal_solver)
|
||||
solver = LearningSolver(
|
||||
solver=internal_solver,
|
||||
solve_lp_first=False,
|
||||
)
|
||||
solver.solve(instance)
|
||||
solver.fit([instance])
|
||||
solver.solve(instance)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="miplearn.solvers.tests" href="index.html">miplearn.solvers.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="miplearn.solvers.tests.test_learning_solver.test_learning_solver" href="#miplearn.solvers.tests.test_learning_solver.test_learning_solver">test_learning_solver</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.tests.test_learning_solver.test_parallel_solve" href="#miplearn.solvers.tests.test_learning_solver.test_parallel_solve">test_parallel_solve</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.tests.test_learning_solver.test_simulate_perfect" href="#miplearn.solvers.tests.test_learning_solver.test_simulate_perfect">test_simulate_perfect</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.tests.test_learning_solver.test_solve_fit_from_disk" href="#miplearn.solvers.tests.test_learning_solver.test_solve_fit_from_disk">test_solve_fit_from_disk</a></code></li>
|
||||
<li><code><a title="miplearn.solvers.tests.test_learning_solver.test_solve_without_lp" href="#miplearn.solvers.tests.test_learning_solver.test_solve_without_lp">test_solve_without_lp</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.7.0</a>.</p>
|
||||
</footer>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad()</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user