mirror of
https://github.com/ANL-CEEESA/MIPLearn.git
synced 2025-12-06 09:28:51 -06:00
Add XpressPyomoSolver
This commit is contained in:
@@ -181,18 +181,27 @@ class BasePyomoSolver(InternalSolver):
|
||||
if not should_repeat:
|
||||
break
|
||||
log = streams[0].getvalue()
|
||||
return {
|
||||
stats = {
|
||||
"Lower bound": results["Problem"][0]["Lower bound"],
|
||||
"Upper bound": results["Problem"][0]["Upper bound"],
|
||||
"Wallclock time": total_wallclock_time,
|
||||
"Nodes": self._extract_node_count(log),
|
||||
"Sense": self._obj_sense,
|
||||
"Log": log,
|
||||
"Warm start value": self._extract_warm_start_value(log),
|
||||
}
|
||||
node_count = self._extract_node_count(log)
|
||||
if node_count is not None:
|
||||
stats["Nodes"] = node_count
|
||||
|
||||
ws_value = self._extract_warm_start_value(log)
|
||||
if ws_value is not None:
|
||||
stats["Warm start value"] = ws_value
|
||||
|
||||
return stats
|
||||
|
||||
@staticmethod
|
||||
def __extract(log, regexp, default=None):
|
||||
if regexp is None:
|
||||
return default
|
||||
value = default
|
||||
for line in log.splitlines():
|
||||
matches = re.findall(regexp, line)
|
||||
@@ -208,18 +217,16 @@ class BasePyomoSolver(InternalSolver):
|
||||
return value
|
||||
|
||||
def _extract_node_count(self, log):
|
||||
return int(self.__extract(log, self._get_node_count_regexp(), default=1))
|
||||
return self.__extract(log, self._get_node_count_regexp())
|
||||
|
||||
def get_constraint_ids(self):
|
||||
return list(self._cname_to_constr.keys())
|
||||
|
||||
@abstractmethod
|
||||
def _get_warm_start_regexp(self):
|
||||
pass
|
||||
return None
|
||||
|
||||
@abstractmethod
|
||||
def _get_node_count_regexp(self):
|
||||
pass
|
||||
return None
|
||||
|
||||
def extract_constraint(self, cid):
|
||||
raise Exception("Not implemented")
|
||||
|
||||
34
miplearn/solvers/pyomo/xpress.py
Normal file
34
miplearn/solvers/pyomo/xpress.py
Normal file
@@ -0,0 +1,34 @@
|
||||
# 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 sys
|
||||
import logging
|
||||
from io import StringIO
|
||||
from pyomo import environ as pe
|
||||
from scipy.stats import randint
|
||||
|
||||
from .base import BasePyomoSolver
|
||||
from .. import RedirectOutput
|
||||
|
||||
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=None):
|
||||
super().__init__(
|
||||
solver_factory=pe.SolverFactory("xpress_persistent"),
|
||||
params={
|
||||
"randomseed": randint(low=0, high=1000).rvs(),
|
||||
},
|
||||
)
|
||||
@@ -5,6 +5,7 @@
|
||||
from inspect import isclass
|
||||
from miplearn import BasePyomoSolver, GurobiSolver, GurobiPyomoSolver
|
||||
from miplearn.problems.knapsack import KnapsackInstance, GurobiKnapsackInstance
|
||||
from miplearn.solvers.pyomo.xpress import XpressPyomoSolver
|
||||
|
||||
|
||||
def _get_instance(solver):
|
||||
@@ -31,4 +32,4 @@ def _get_instance(solver):
|
||||
|
||||
|
||||
def _get_internal_solvers():
|
||||
return [GurobiPyomoSolver, GurobiSolver]
|
||||
return [GurobiPyomoSolver, GurobiSolver, XpressPyomoSolver]
|
||||
|
||||
@@ -43,7 +43,8 @@ def test_internal_solver_warm_starts():
|
||||
}
|
||||
)
|
||||
stats = solver.solve(tee=True)
|
||||
assert stats["Warm start value"] == 725.0
|
||||
if "Warm start value" in stats:
|
||||
assert stats["Warm start value"] == 725.0
|
||||
|
||||
solver.set_warm_start(
|
||||
{
|
||||
@@ -56,7 +57,8 @@ def test_internal_solver_warm_starts():
|
||||
}
|
||||
)
|
||||
stats = solver.solve(tee=True)
|
||||
assert stats["Warm start value"] is None
|
||||
if "Warm start value" in stats:
|
||||
assert stats["Warm start value"] is None
|
||||
|
||||
solver.fix(
|
||||
{
|
||||
@@ -97,7 +99,6 @@ def test_internal_solver():
|
||||
assert stats["Upper bound"] == 1183.0
|
||||
assert stats["Sense"] == "max"
|
||||
assert isinstance(stats["Wallclock time"], float)
|
||||
assert isinstance(stats["Nodes"], int)
|
||||
|
||||
solution = solver.get_solution()
|
||||
assert solution["x"][0] == 1.0
|
||||
|
||||
Reference in New Issue
Block a user