Edit on GitHub

boundml.instances

 1from .ecole_instances import *
 2from .instances import *
 3from .miplib import *
 4from .folder_instances import *
 5
 6__all__ = [
 7    "Instances",
 8    "FolderInstances",
 9    "MipLibInstances",
10] + [
11    "CapacitatedFacilityLocationGenerator",
12    "CombinatorialAuctionGenerator",
13    "IndependentSetGenerator",
14    "SetCoverGenerator"
15] if HAS_ECOLE_FORK else []
class Instances(abc.ABC):
 7class Instances(ABC):
 8    """
 9    An Instances object is an iterator that yields pyscipopt.Model or path to an instance.
10    """
11    def __iter__(self):
12        return self
13
14    @abstractmethod
15    def __next__(self) -> Model | str :
16        raise NotImplementedError("Subclasses must implement this method.")

An Instances object is an iterator that yields pyscipopt.Model or path to an instance.

class FolderInstances(boundml.instances.Instances):
13class FolderInstances(Instances):
14    """
15    FolderInstances allows to iterate through the instances in a folder.
16    """
17
18    def __init__(self, folder: str, filter: Callable[[str], bool] = lambda x: True, allow_reading_error=True):
19        """
20        Parameters
21        ----------
22        folder : str
23            Name of the folder containing the instances.
24        filter : Callable[[str], bool]
25            Filter instances based on their name to work only with a desired subset of instances
26        allow_reading_error: bool
27            If True and SCIP failed to read a problem, catch the error and go to the next one.
28        """
29        self._instances_dir = folder
30
31        self._instances_files = [name for name in os.listdir(self._instances_dir) if filter(name)]
32        self._instances_files.sort()
33        self._index = 0
34        self.allow_reading_error = allow_reading_error
35
36    def __next__(self) -> str:
37        if self._index >= len(self._instances_files):
38            raise StopIteration
39
40        path = os.path.join(self._instances_dir, self._instances_files[self._index])
41        self._index += 1
42        model = Model()
43        model.setParam("display/verblevel", 0)
44
45        if self.allow_reading_error:
46            is_valid = check_readability(path)
47
48            if not is_valid:
49                warnings.warn(
50                    f"Failed to read problem {path}." + "Skipping to the next one." if self.allow_reading_error else "")
51                return next(self)
52
53        return path
54
55    def seed(self, seed: int):
56        """
57        Shuffle the instances based on the given seed
58        Parameters
59        ----------
60        seed : int
61        """
62        random.Random(seed).shuffle(self._instances_files)
63        self._index = 0
64
65    def __len__(self):
66        return len(self._instances_files)

FolderInstances allows to iterate through the instances in a folder.

FolderInstances( folder: str, filter: Callable[[str], bool] = <function FolderInstances.<lambda>>, allow_reading_error=True)
18    def __init__(self, folder: str, filter: Callable[[str], bool] = lambda x: True, allow_reading_error=True):
19        """
20        Parameters
21        ----------
22        folder : str
23            Name of the folder containing the instances.
24        filter : Callable[[str], bool]
25            Filter instances based on their name to work only with a desired subset of instances
26        allow_reading_error: bool
27            If True and SCIP failed to read a problem, catch the error and go to the next one.
28        """
29        self._instances_dir = folder
30
31        self._instances_files = [name for name in os.listdir(self._instances_dir) if filter(name)]
32        self._instances_files.sort()
33        self._index = 0
34        self.allow_reading_error = allow_reading_error
Parameters
  • folder (str): Name of the folder containing the instances.
  • filter (Callable[[str], bool]): Filter instances based on their name to work only with a desired subset of instances
  • allow_reading_error (bool): If True and SCIP failed to read a problem, catch the error and go to the next one.
allow_reading_error
def seed(self, seed: int):
55    def seed(self, seed: int):
56        """
57        Shuffle the instances based on the given seed
58        Parameters
59        ----------
60        seed : int
61        """
62        random.Random(seed).shuffle(self._instances_files)
63        self._index = 0

Shuffle the instances based on the given seed

Parameters
  • seed (int):
class MipLibInstances(boundml.instances.FolderInstances):
 17class MipLibInstances(FolderInstances):
 18    """
 19    MipLibInstances allow to iterate through MipLib instances.
 20    It downloads archive files once and cache it as long with all the extracted instances.
 21    It is highly recommended to use the argument force_download and force_extract if the process is killed while
 22    performing one of these operations.
 23    By default, MipLibInstances iterates through the instances ordered by alphabetical order, a seed can be set to
 24    randomize the order.
 25    """
 26    _archives_urls = {
 27        "collection": "https://miplib.zib.de/downloads/collection.zip",
 28        "benchmark": "https://miplib.zib.de/downloads/benchmark.zip"
 29    }
 30
 31    def __init__(self, subset: str = "benchmark", force_download: bool = False, force_extract: bool = False,
 32                 filter: Callable[[str], bool] = lambda x: True, allow_reading_error=True):
 33        """
 34        Parameters
 35        ----------
 36        subset : str
 37            Name of the subset of instances to used, either "collection" or "benchmark"
 38        force_download : bool
 39            Force the download even if the file already exists.
 40        force_extract : bool
 41            Force the extraction even if the folder already exists.
 42        filter : Callable[[str], bool]
 43            Filter instances based on their name (name.mps) to work only with a desired subset of instances
 44        """
 45        # Create a cache directory specific to your library
 46        self._cache_dir = Path(user_cache_dir("boundml"))
 47        self._cache_dir.mkdir(parents=True, exist_ok=True)
 48        self._zip_file = self._cache_dir.joinpath(f"{subset}.zip")
 49        self._instances_dir = self._cache_dir.joinpath(f"{subset}")
 50
 51        if subset in MipLibInstances._archives_urls:
 52            url = MipLibInstances._archives_urls[subset]
 53        else:
 54            raise ValueError(f"Unknown subset: {subset}. Must be one of {MipLibInstances._archives_urls}")
 55
 56        self._download(url, force_download)
 57        self._extract(force_download or force_extract)
 58
 59        super().__init__(str(self._instances_dir), filter, allow_reading_error=allow_reading_error)
 60
 61    def _download(self, url: str, force: bool = False):
 62        if force or not self._zip_file.exists():
 63            resp = requests.get(url, stream=True)
 64            total = int(resp.headers.get('content-length', 0))
 65            with open(self._zip_file, 'wb') as file, tqdm(
 66                    desc=str("Downloading MIPLIB instances"),
 67                    total=total,
 68                    unit='iB',
 69                    unit_scale=True,
 70                    unit_divisor=1024,
 71            ) as bar:
 72                for data in resp.iter_content(chunk_size=1024):
 73                    size = file.write(data)
 74                    bar.update(size)
 75
 76    def _extract(self, force: bool = False):
 77        if force or not self._instances_dir.exists():
 78            if self._instances_dir.exists():
 79                shutil.rmtree(self._instances_dir)
 80
 81            print("Extracting collections.zip...")
 82            self._instances_dir.mkdir(exist_ok=True)
 83            with zipfile.ZipFile(self._zip_file, 'r') as zip_ref:
 84                zip_ref.extractall(self._instances_dir)
 85
 86            files = os.listdir(self._instances_dir)
 87            with tqdm(
 88                    desc=str("Extracting instances"),
 89                    total=len(files),
 90                    unit='it',
 91                    unit_scale=True,
 92                    unit_divisor=1,
 93            ) as bar:
 94                for file in files:
 95                    path = os.path.join(self._instances_dir, file)
 96                    dest_path = ".".join(path.split(".")[:-1])
 97                    with gzip.open(path, 'rb') as f_in:
 98                        with open(dest_path, 'wb') as f_out:
 99                            shutil.copyfileobj(f_in, f_out)
100                    os.remove(path)
101
102                    bar.update(1)

MipLibInstances allow to iterate through MipLib instances. It downloads archive files once and cache it as long with all the extracted instances. It is highly recommended to use the argument force_download and force_extract if the process is killed while performing one of these operations. By default, MipLibInstances iterates through the instances ordered by alphabetical order, a seed can be set to randomize the order.

MipLibInstances( subset: str = 'benchmark', force_download: bool = False, force_extract: bool = False, filter: Callable[[str], bool] = <function MipLibInstances.<lambda>>, allow_reading_error=True)
31    def __init__(self, subset: str = "benchmark", force_download: bool = False, force_extract: bool = False,
32                 filter: Callable[[str], bool] = lambda x: True, allow_reading_error=True):
33        """
34        Parameters
35        ----------
36        subset : str
37            Name of the subset of instances to used, either "collection" or "benchmark"
38        force_download : bool
39            Force the download even if the file already exists.
40        force_extract : bool
41            Force the extraction even if the folder already exists.
42        filter : Callable[[str], bool]
43            Filter instances based on their name (name.mps) to work only with a desired subset of instances
44        """
45        # Create a cache directory specific to your library
46        self._cache_dir = Path(user_cache_dir("boundml"))
47        self._cache_dir.mkdir(parents=True, exist_ok=True)
48        self._zip_file = self._cache_dir.joinpath(f"{subset}.zip")
49        self._instances_dir = self._cache_dir.joinpath(f"{subset}")
50
51        if subset in MipLibInstances._archives_urls:
52            url = MipLibInstances._archives_urls[subset]
53        else:
54            raise ValueError(f"Unknown subset: {subset}. Must be one of {MipLibInstances._archives_urls}")
55
56        self._download(url, force_download)
57        self._extract(force_download or force_extract)
58
59        super().__init__(str(self._instances_dir), filter, allow_reading_error=allow_reading_error)
Parameters
  • subset (str): Name of the subset of instances to used, either "collection" or "benchmark"
  • force_download (bool): Force the download even if the file already exists.
  • force_extract (bool): Force the extraction even if the folder already exists.
  • filter (Callable[[str], bool]): Filter instances based on their name (name.mps) to work only with a desired subset of instances
class CapacitatedFacilityLocationGenerator(boundml.instances.ecole_instances.EcoleInstances):
23class CapacitatedFacilityLocationGenerator(EcoleInstances):
24    def __init__(self, *args, **kwargs):
25        super().__init__(ecole.instance.CapacitatedFacilityLocationGenerator(*args, **kwargs))

An Instances object is an iterator that yields pyscipopt.Model or path to an instance.

CapacitatedFacilityLocationGenerator(*args, **kwargs)
24    def __init__(self, *args, **kwargs):
25        super().__init__(ecole.instance.CapacitatedFacilityLocationGenerator(*args, **kwargs))
class CombinatorialAuctionGenerator(boundml.instances.ecole_instances.EcoleInstances):
27class CombinatorialAuctionGenerator(EcoleInstances):
28    def __init__(self, *args, **kwargs):
29        super().__init__(ecole.instance.CombinatorialAuctionGenerator(*args, **kwargs))

An Instances object is an iterator that yields pyscipopt.Model or path to an instance.

CombinatorialAuctionGenerator(*args, **kwargs)
28    def __init__(self, *args, **kwargs):
29        super().__init__(ecole.instance.CombinatorialAuctionGenerator(*args, **kwargs))
class IndependentSetGenerator(boundml.instances.ecole_instances.EcoleInstances):
31class IndependentSetGenerator(EcoleInstances):
32    def __init__(self, *args, **kwargs):
33        super().__init__(ecole.instance.IndependentSetGenerator(*args, **kwargs))

An Instances object is an iterator that yields pyscipopt.Model or path to an instance.

IndependentSetGenerator(*args, **kwargs)
32    def __init__(self, *args, **kwargs):
33        super().__init__(ecole.instance.IndependentSetGenerator(*args, **kwargs))
class SetCoverGenerator(boundml.instances.ecole_instances.EcoleInstances):
35class SetCoverGenerator(EcoleInstances):
36    def __init__(self, *args, **kwargs):
37        super().__init__(ecole.instance.SetCoverGenerator(*args, **kwargs))

An Instances object is an iterator that yields pyscipopt.Model or path to an instance.

SetCoverGenerator(*args, **kwargs)
36    def __init__(self, *args, **kwargs):
37        super().__init__(ecole.instance.SetCoverGenerator(*args, **kwargs))