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 []
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.
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.
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.
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):
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.
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
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.
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.
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.
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.