Reorganize instance package

This commit is contained in:
2021-04-06 16:31:47 -05:00
parent 3543a2ba92
commit f90f295620
31 changed files with 177 additions and 169 deletions

View File

@@ -3,15 +3,9 @@
# Released under the modified BSD license. See COPYING.md for more details.
from .benchmark import BenchmarkRunner
from .classifiers import (
Classifier,
Regressor,
)
from .classifiers import Classifier, Regressor
from .classifiers.adaptive import AdaptiveClassifier
from .classifiers.sklearn import (
ScikitLearnRegressor,
ScikitLearnClassifier,
)
from .classifiers.sklearn import ScikitLearnRegressor, ScikitLearnClassifier
from .classifiers.threshold import MinPrecisionThreshold
from .components.component import Component
from .components.dynamic_lazy import DynamicLazyConstraintsComponent
@@ -22,12 +16,12 @@ from .components.static_lazy import StaticLazyConstraintsComponent
from .components.steps.convert_tight import ConvertTightIneqsIntoEqsStep
from .components.steps.drop_redundant import DropRedundantInequalitiesStep
from .components.steps.relax_integrality import RelaxIntegralityStep
from .instance import (
Instance,
from .instance.base import Instance
from .instance.picklegz import (
PickleGzInstance,
write_pickle_gz,
write_pickle_gz_multiple,
read_pickle_gz,
write_pickle_gz_multiple,
)
from .log import setup_logger
from .solvers.gurobi import GurobiSolver

View File

@@ -8,7 +8,7 @@ from typing import Dict, List
import pandas as pd
from miplearn.instance import Instance
from miplearn.instance.base import Instance
from miplearn.solvers.learning import LearningSolver
logger = logging.getLogger(__name__)

View File

@@ -7,7 +7,7 @@ from typing import Any, List, TYPE_CHECKING, Tuple, Dict, Hashable
import numpy as np
from miplearn.features import TrainingSample, Features
from miplearn.instance import Instance
from miplearn.instance.base import Instance
from miplearn.types import LearningSolveStats
if TYPE_CHECKING:

View File

@@ -12,7 +12,7 @@ from miplearn.classifiers import Regressor
from miplearn.classifiers.sklearn import ScikitLearnRegressor
from miplearn.components.component import Component
from miplearn.features import TrainingSample, Features
from miplearn.instance import Instance
from miplearn.instance.base import Instance
from miplearn.types import LearningSolveStats
if TYPE_CHECKING:

View File

@@ -21,7 +21,7 @@ from miplearn.classifiers.threshold import MinPrecisionThreshold, Threshold
from miplearn.components import classifier_evaluation_dict
from miplearn.components.component import Component
from miplearn.features import TrainingSample, Features
from miplearn.instance import Instance
from miplearn.instance.base import Instance
from miplearn.types import (
Solution,
LearningSolveStats,

View File

@@ -11,7 +11,7 @@ from miplearn.types import VarIndex, Solution
if TYPE_CHECKING:
from miplearn.solvers.internal import InternalSolver
from miplearn.instance import Instance
from miplearn.instance.base import Instance
@dataclass

View File

@@ -0,0 +1,3 @@
# MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
# Copyright (C) 2020-2021, UChicago Argonne, LLC. All rights reserved.
# Released under the modified BSD license. See COPYING.md for more details.

View File

@@ -2,12 +2,9 @@
# Copyright (C) 2020-2021, UChicago Argonne, LLC. All rights reserved.
# Released under the modified BSD license. See COPYING.md for more details.
import gzip
import logging
import os
import pickle
from abc import ABC, abstractmethod
from typing import Any, List, Optional, Hashable, IO, cast
from typing import Any, List, Optional, Hashable
from miplearn.features import TrainingSample, Features
from miplearn.types import VarIndex
@@ -15,29 +12,11 @@ from miplearn.types import VarIndex
logger = logging.getLogger(__name__)
def write_pickle_gz(obj: Any, filename: str) -> None:
logger.info(f"Writing: {filename}")
os.makedirs(os.path.dirname(filename), exist_ok=True)
with gzip.GzipFile(filename, "wb") as file:
pickle.dump(obj, cast(IO[bytes], file))
def read_pickle_gz(filename: str) -> Any:
logger.info(f"Reading: {filename}")
with gzip.GzipFile(filename, "rb") as file:
return pickle.load(cast(IO[bytes], file))
def write_pickle_gz_multiple(objs: List[Any], dirname: str) -> None:
for (i, obj) in enumerate(objs):
write_pickle_gz(obj, f"{dirname}/{i:05d}.pkl.gz")
# noinspection PyMethodMayBeStatic
class Instance(ABC):
"""
Abstract class holding all the data necessary to generate a concrete model of the
problem.
proble.
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
@@ -184,111 +163,3 @@ class Instance(ABC):
Save any pending changes made to the instance to the underlying data store.
"""
pass
def lazy_load(func):
def inner(self, *args):
if self.instance is None:
self.instance = self._load()
self.features = self.instance.features
self.training_data = self.instance.training_data
return func(self, *args)
return inner
class PickleGzInstance(Instance):
"""
An instance backed by a gzipped pickle file.
The instance is only loaded to memory after an operation is called (for example,
`to_model`).
Parameters
----------
filename: str
Path of the gzipped pickle file that should be loaded.
"""
# noinspection PyMissingConstructor
def __init__(self, filename: str) -> None:
assert os.path.exists(filename), f"File not found: {filename}"
self.instance: Optional[Instance] = None
self.filename: str = filename
@lazy_load
def to_model(self) -> Any:
assert self.instance is not None
return self.instance.to_model()
@lazy_load
def get_instance_features(self) -> List[float]:
assert self.instance is not None
return self.instance.get_instance_features()
@lazy_load
def get_variable_features(self, var_name: str, index: VarIndex) -> List[float]:
assert self.instance is not None
return self.instance.get_variable_features(var_name, index)
@lazy_load
def get_variable_category(
self,
var_name: str,
index: VarIndex,
) -> Optional[Hashable]:
assert self.instance is not None
return self.instance.get_variable_category(var_name, index)
@lazy_load
def get_constraint_features(self, cid: str) -> Optional[List[float]]:
assert self.instance is not None
return self.instance.get_constraint_features(cid)
@lazy_load
def get_constraint_category(self, cid: str) -> Optional[Hashable]:
assert self.instance is not None
return self.instance.get_constraint_category(cid)
@lazy_load
def has_static_lazy_constraints(self) -> bool:
assert self.instance is not None
return self.instance.has_static_lazy_constraints()
@lazy_load
def has_dynamic_lazy_constraints(self):
assert self.instance is not None
return self.instance.has_dynamic_lazy_constraints()
@lazy_load
def is_constraint_lazy(self, cid: str) -> bool:
assert self.instance is not None
return self.instance.is_constraint_lazy(cid)
@lazy_load
def find_violated_lazy_constraints(self, model):
assert self.instance is not None
return self.instance.find_violated_lazy_constraints(model)
@lazy_load
def build_lazy_constraint(self, model, violation):
assert self.instance is not None
return self.instance.build_lazy_constraint(model, violation)
@lazy_load
def find_violated_user_cuts(self, model):
assert self.instance is not None
return self.instance.find_violated_user_cuts(model)
@lazy_load
def build_user_cut(self, model, violation):
assert self.instance is not None
return self.instance.build_user_cut(model, violation)
def _load(self) -> Instance:
obj = read_pickle_gz(self.filename)
assert isinstance(obj, Instance)
return obj
def flush(self) -> None:
write_pickle_gz(self.instance, self.filename)

View File

@@ -0,0 +1,137 @@
# MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
# Copyright (C) 2020-2021, UChicago Argonne, LLC. All rights reserved.
# Released under the modified BSD license. See COPYING.md for more details.
import gzip
import os
import pickle
from typing import Optional, Any, List, Hashable, cast, IO
from miplearn.instance.base import logger, Instance
from miplearn.types import VarIndex
def lazy_load(func):
def inner(self, *args):
if self.instance is None:
self.instance = self._load()
self.features = self.instance.features
self.training_data = self.instance.training_data
return func(self, *args)
return inner
class PickleGzInstance(Instance):
"""
An instance backed by a gzipped pickle file.
The instance is only loaded to memory after an operation is called (for example,
`to_model`).
Parameters
----------
filename: str
Path of the gzipped pickle file that should be loaded.
"""
# noinspection PyMissingConstructor
def __init__(self, filename: str) -> None:
assert os.path.exists(filename), f"File not found: {filename}"
self.instance: Optional[Instance] = None
self.filename: str = filename
@lazy_load
def to_model(self) -> Any:
assert self.instance is not None
return self.instance.to_model()
@lazy_load
def get_instance_features(self) -> List[float]:
assert self.instance is not None
return self.instance.get_instance_features()
@lazy_load
def get_variable_features(self, var_name: str, index: VarIndex) -> List[float]:
assert self.instance is not None
return self.instance.get_variable_features(var_name, index)
@lazy_load
def get_variable_category(
self,
var_name: str,
index: VarIndex,
) -> Optional[Hashable]:
assert self.instance is not None
return self.instance.get_variable_category(var_name, index)
@lazy_load
def get_constraint_features(self, cid: str) -> Optional[List[float]]:
assert self.instance is not None
return self.instance.get_constraint_features(cid)
@lazy_load
def get_constraint_category(self, cid: str) -> Optional[Hashable]:
assert self.instance is not None
return self.instance.get_constraint_category(cid)
@lazy_load
def has_static_lazy_constraints(self) -> bool:
assert self.instance is not None
return self.instance.has_static_lazy_constraints()
@lazy_load
def has_dynamic_lazy_constraints(self):
assert self.instance is not None
return self.instance.has_dynamic_lazy_constraints()
@lazy_load
def is_constraint_lazy(self, cid: str) -> bool:
assert self.instance is not None
return self.instance.is_constraint_lazy(cid)
@lazy_load
def find_violated_lazy_constraints(self, model):
assert self.instance is not None
return self.instance.find_violated_lazy_constraints(model)
@lazy_load
def build_lazy_constraint(self, model, violation):
assert self.instance is not None
return self.instance.build_lazy_constraint(model, violation)
@lazy_load
def find_violated_user_cuts(self, model):
assert self.instance is not None
return self.instance.find_violated_user_cuts(model)
@lazy_load
def build_user_cut(self, model, violation):
assert self.instance is not None
return self.instance.build_user_cut(model, violation)
def _load(self) -> Instance:
obj = read_pickle_gz(self.filename)
assert isinstance(obj, Instance)
return obj
def flush(self) -> None:
write_pickle_gz(self.instance, self.filename)
def write_pickle_gz(obj: Any, filename: str) -> None:
logger.info(f"Writing: {filename}")
os.makedirs(os.path.dirname(filename), exist_ok=True)
with gzip.GzipFile(filename, "wb") as file:
pickle.dump(obj, cast(IO[bytes], file))
def read_pickle_gz(filename: str) -> Any:
logger.info(f"Reading: {filename}")
with gzip.GzipFile(filename, "rb") as file:
return pickle.load(cast(IO[bytes], file))
def write_pickle_gz_multiple(objs: List[Any], dirname: str) -> None:
for (i, obj) in enumerate(objs):
write_pickle_gz(obj, f"{dirname}/{i:05d}.pkl.gz")

View File

@@ -8,7 +8,7 @@ import pyomo.environ as pe
from scipy.stats import uniform, randint
from scipy.stats.distributions import rv_frozen
from miplearn.instance import Instance
from miplearn.instance.base import Instance
class ChallengeA:

View File

@@ -8,7 +8,7 @@ import pyomo.environ as pe
from scipy.stats import uniform, randint
from scipy.stats.distributions import rv_frozen
from miplearn.instance import Instance
from miplearn.instance.base import Instance
class ChallengeA:

View File

@@ -9,7 +9,7 @@ from scipy.spatial.distance import pdist, squareform
from scipy.stats import uniform, randint
from scipy.stats.distributions import rv_frozen
from miplearn.instance import Instance
from miplearn.instance.base import Instance
class ChallengeA:

View File

@@ -8,7 +8,7 @@ from io import StringIO
from random import randint
from typing import List, Any, Dict, Optional, cast, Tuple, Union
from miplearn.instance import Instance
from miplearn.instance.base import Instance
from miplearn.solvers import _RedirectOutput
from miplearn.solvers.internal import (
InternalSolver,

View File

@@ -6,7 +6,7 @@ import logging
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional
from miplearn.instance import Instance
from miplearn.instance.base import Instance
from miplearn.types import (
LPSolveStats,
IterationCallback,

View File

@@ -14,7 +14,8 @@ from miplearn.components.dynamic_user_cuts import UserCutsComponent
from miplearn.components.objective import ObjectiveValueComponent
from miplearn.components.primal import PrimalSolutionComponent
from miplearn.features import FeaturesExtractor, TrainingSample
from miplearn.instance import Instance, PickleGzInstance
from miplearn.instance.base import Instance
from miplearn.instance.picklegz import PickleGzInstance
from miplearn.solvers import _RedirectOutput
from miplearn.solvers.internal import InternalSolver
from miplearn.solvers.pyomo.gurobi import GurobiPyomoSolver

View File

@@ -14,7 +14,7 @@ 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.instance.base import Instance
from miplearn.solvers import _RedirectOutput
from miplearn.solvers.internal import (
InternalSolver,