diff --git a/src/python/miplearn/__init__.py b/src/python/miplearn/__init__.py index dc6607d..b519bca 100644 --- a/src/python/miplearn/__init__.py +++ b/src/python/miplearn/__init__.py @@ -12,7 +12,8 @@ from .components.objective import ObjectiveValueComponent from .components.lazy import LazyConstraintsComponent from .components.cuts import UserCutsComponent from .components.primal import PrimalSolutionComponent -from .components.branching import BranchPriorityComponent, BranchPriorityExtractor +from .components.branching import (BranchPriorityComponent, + BranchPriorityExtractor) from .classifiers.adaptive import AdaptiveClassifier from .classifiers.threshold import MinPrecisionThreshold @@ -21,7 +22,8 @@ from .benchmark import BenchmarkRunner from .instance import Instance -from .solvers.learning import LearningSolver -from .solvers.cplex import CPLEXSolver -from .solvers.gurobi import GurobiSolver +from .solvers.pyomo.base import BasePyomoSolver +from .solvers.pyomo.cplex import CplexPyomoSolver +from .solvers.pyomo.gurobi import GurobiPyomoSolver from .solvers.internal import InternalSolver +from .solvers.learning import LearningSolver diff --git a/src/python/miplearn/components/tests/test_cuts.py b/src/python/miplearn/components/tests/test_cuts.py index 7ec32f9..66b38c9 100644 --- a/src/python/miplearn/components/tests/test_cuts.py +++ b/src/python/miplearn/components/tests/test_cuts.py @@ -4,7 +4,7 @@ import numpy as np import pyomo.environ as pe -from miplearn import Instance, GurobiSolver, LearningSolver +from miplearn import Instance, GurobiPyomoSolver, LearningSolver from miplearn.problems.knapsack import ChallengeA @@ -25,7 +25,7 @@ class CutInstance(Instance): def test_cut(): challenge = ChallengeA() - gurobi = GurobiSolver() + gurobi = GurobiPyomoSolver() solver = LearningSolver(solver=gurobi, time_limit=10) solver.solve(challenge.training_instances[0]) # assert False diff --git a/src/python/miplearn/solvers/learning.py b/src/python/miplearn/solvers/learning.py index 1e3321a..a150781 100644 --- a/src/python/miplearn/solvers/learning.py +++ b/src/python/miplearn/solvers/learning.py @@ -5,15 +5,14 @@ import logging from copy import deepcopy from typing import Optional, List - from p_tqdm import p_map -from .cplex import CPLEXSolver -from .gurobi import GurobiSolver from .. import (ObjectiveValueComponent, PrimalSolutionComponent, LazyConstraintsComponent, UserCutsComponent) +from .pyomo.cplex import CplexPyomoSolver +from .pyomo.gurobi import GurobiPyomoSolver logger = logging.getLogger(__name__) @@ -77,9 +76,9 @@ class LearningSolver: def _create_internal_solver(self): logger.debug("Initializing %s" % self.internal_solver_factory) if self.internal_solver_factory == "cplex": - solver = CPLEXSolver() + solver = CplexPyomoSolver() elif self.internal_solver_factory == "gurobi": - solver = GurobiSolver() + solver = GurobiPyomoSolver() elif callable(self.internal_solver_factory): solver = self.internal_solver_factory() else: diff --git a/src/python/miplearn/solvers/pyomo/__init__.py b/src/python/miplearn/solvers/pyomo/__init__.py new file mode 100644 index 0000000..13c148b --- /dev/null +++ b/src/python/miplearn/solvers/pyomo/__init__.py @@ -0,0 +1,3 @@ +# 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. diff --git a/src/python/miplearn/solvers/pyomo.py b/src/python/miplearn/solvers/pyomo/base.py similarity index 96% rename from src/python/miplearn/solvers/pyomo.py rename to src/python/miplearn/solvers/pyomo/base.py index 676252a..9d7a23b 100644 --- a/src/python/miplearn/solvers/pyomo.py +++ b/src/python/miplearn/solvers/pyomo/base.py @@ -2,24 +2,27 @@ # 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 +import logging +import pyomo from abc import abstractmethod from io import StringIO - -import pyomo -import pyomo.environ as pe +from pyomo import environ as pe from pyomo.core import Var -from . import RedirectOutput -from .internal import InternalSolver -from ..instance import Instance +from .. import RedirectOutput +from ..internal import InternalSolver +from ...instance import Instance logger = logging.getLogger(__name__) -class PyomoSolver(InternalSolver): +class BasePyomoSolver(InternalSolver): + """ + Base class for all Pyomo solvers. + """ + def __init__(self): self.instance = None self.model = None diff --git a/src/python/miplearn/solvers/cplex.py b/src/python/miplearn/solvers/pyomo/cplex.py similarity index 89% rename from src/python/miplearn/solvers/cplex.py rename to src/python/miplearn/solvers/pyomo/cplex.py index af47761..952643b 100644 --- a/src/python/miplearn/solvers/cplex.py +++ b/src/python/miplearn/solvers/pyomo/cplex.py @@ -2,16 +2,16 @@ # Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved. # Released under the modified BSD license. See COPYING.md for more details. -import pyomo.environ as pe +from pyomo import environ as pe from scipy.stats import randint -from .pyomo import PyomoSolver +from .base import BasePyomoSolver -class CPLEXSolver(PyomoSolver): +class CplexPyomoSolver(BasePyomoSolver): def __init__(self, options=None): """ - Creates a new CPLEXSolver. + Creates a new CPLEX solver, accessed through Pyomo. Parameters ---------- @@ -47,4 +47,3 @@ class CPLEXSolver(PyomoSolver): def set_branching_priorities(self, priorities): raise NotImplementedError - diff --git a/src/python/miplearn/solvers/gurobi.py b/src/python/miplearn/solvers/pyomo/gurobi.py similarity index 95% rename from src/python/miplearn/solvers/gurobi.py rename to src/python/miplearn/solvers/pyomo/gurobi.py index 83a619e..7b55f6c 100644 --- a/src/python/miplearn/solvers/gurobi.py +++ b/src/python/miplearn/solvers/pyomo/gurobi.py @@ -2,25 +2,24 @@ # 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 +import logging from io import StringIO - -import pyomo.environ as pe -from miplearn.solvers import RedirectOutput +from pyomo import environ as pe from scipy.stats import randint -from .pyomo import PyomoSolver +from .base import BasePyomoSolver +from .. import RedirectOutput logger = logging.getLogger(__name__) -class GurobiSolver(PyomoSolver): +class GurobiPyomoSolver(BasePyomoSolver): def __init__(self, use_lazy_callbacks=True, options=None): """ - Creates a new GurobiSolver. + Creates a new Gurobi solver, accessed through Pyomo. Parameters ---------- diff --git a/src/python/miplearn/solvers/tests/test_internal_solver.py b/src/python/miplearn/solvers/tests/test_internal_solver.py index 3715fd3..77b8def 100644 --- a/src/python/miplearn/solvers/tests/test_internal_solver.py +++ b/src/python/miplearn/solvers/tests/test_internal_solver.py @@ -5,8 +5,7 @@ from io import StringIO import pyomo.environ as pe from miplearn.solvers import RedirectOutput -from miplearn.solvers.cplex import CPLEXSolver -from miplearn.solvers.gurobi import GurobiSolver +from miplearn import CplexPyomoSolver, GurobiPyomoSolver from . import _get_instance from ...problems.knapsack import ChallengeA @@ -23,7 +22,7 @@ def test_redirect_output(): def test_internal_solver_warm_starts(): - for solver in [GurobiSolver(), CPLEXSolver()]: + for solver in [GurobiPyomoSolver(), CplexPyomoSolver()]: instance = _get_instance() model = instance.to_model() @@ -64,7 +63,7 @@ def test_internal_solver_warm_starts(): def test_internal_solver(): - for solver in [GurobiSolver(), CPLEXSolver()]: + for solver in [GurobiPyomoSolver(), CplexPyomoSolver()]: instance = _get_instance() model = instance.to_model() @@ -99,9 +98,9 @@ def test_internal_solver(): def test_node_count(): - for solver in [GurobiSolver(), - GurobiSolver(use_lazy_callbacks=False), - CPLEXSolver()]: + for solver in [GurobiPyomoSolver(), + GurobiPyomoSolver(use_lazy_callbacks=False), + CplexPyomoSolver()]: challenge = ChallengeA() solver.set_time_limit(1) solver.set_instance(challenge.test_instances[0]) diff --git a/src/python/miplearn/solvers/tests/test_learning_solver.py b/src/python/miplearn/solvers/tests/test_learning_solver.py index 154a2d9..ab6de6e 100644 --- a/src/python/miplearn/solvers/tests/test_learning_solver.py +++ b/src/python/miplearn/solvers/tests/test_learning_solver.py @@ -5,9 +5,8 @@ import pickle import tempfile -from miplearn import BranchPriorityComponent +from miplearn import BranchPriorityComponent, GurobiPyomoSolver from miplearn import LearningSolver -from miplearn.solvers.gurobi import GurobiSolver from . import _get_instance @@ -15,7 +14,7 @@ from . import _get_instance def test_learning_solver(): instance = _get_instance() for mode in ["exact", "heuristic"]: - for internal_solver in ["cplex", "gurobi", GurobiSolver]: + for internal_solver in ["cplex", "gurobi", GurobiPyomoSolver]: solver = LearningSolver(time_limit=300, gap_tolerance=1e-3, threads=1,