Repository: CharJon/GeCO

Issue:
Expand loader functionality to allow downloads from older miplib libraries
Some instances did rotate out of the current miplib completely. To reproduce experiments of older papers it would be nice to be able do download instances from [2010](http://miplib2010.zib.de/miplib2010.php) and [2003](http://miplib2010.zib.de/miplib2003/miplib2003.php).

Discussion:

Patch:
diff --git a/geco/mips/miplib/base.py b/geco/mips/miplib/base.py
index d0c3cc0..f110683 100644
--- a/geco/mips/miplib/base.py
+++ b/geco/mips/miplib/base.py
@@ -1,11 +1,16 @@
 import tempfile
-from urllib.request import urlretrieve
+from urllib.request import urlretrieve, urlopen
+from urllib.error import URLError
 import pyscipopt as scip
 import os
 
 
 class Loader:
-    INSTANCE_URL = "https://miplib.zib.de/WebData/instances/"
+    INSTANCES_URLS = [
+        "https://miplib.zib.de/WebData/instances/",  # 2017 instances
+        "http://miplib2010.zib.de/download/",  # 2010 instances
+        "http://miplib2010.zib.de/miplib2003/download/",  # 2003 instance
+    ]
 
     def __init__(self, persistent_directory=None):
         """
@@ -38,12 +43,29 @@ class Loader:
         if self.dir:
             return self.dir + instance_name
         else:
-            return tempfile.NamedTemporaryFile(suffix=".mps.gz").name
+            extension = instance_name[instance_name.index(".") :]
+            return tempfile.NamedTemporaryFile(suffix=extension).name
 
     def _download_instance(self, instance_name):
         path = self._generate_path_for_instance(instance_name)
-        urlretrieve(self.INSTANCE_URL + instance_name, path)
-        self.instances_cache[instance_name] = path
+        for url in self.INSTANCES_URLS:
+            download_url = url + instance_name
+            try:
+                response = urlopen(download_url)
+            except URLError:
+                continue
+            if self._successful_response(response):
+                urlretrieve(download_url, path)
+                self.instances_cache[instance_name] = path
+                break
+        else:
+            raise ValueError(
+                "Was not able to find the instance in any of the MIPLIB files"
+            )
+
+    @staticmethod
+    def _successful_response(response):
+        return response.status == 200 and "not_found" not in response.url
 
     def _instance_cached(self, instance_name):
         return instance_name in self.instances_cache


Test patch:
diff --git a/geco/mips/tests/test_miplib.py b/geco/mips/tests/test_miplib.py
index 6757d4c..651eca9 100644
--- a/geco/mips/tests/test_miplib.py
+++ b/geco/mips/tests/test_miplib.py
@@ -1,4 +1,5 @@
 import pandas as pd
+import pytest
 
 from geco.mips.miplib.base import *
 
@@ -39,3 +40,18 @@ def test_persistent_directory():
     )  # instance path loaded correctly into cache
     assert os.path.exists(path)  # instance path exists
     os.unlink(instance_name)  # cleanup local directory
+
+
+def test_not_found_error():
+    with pytest.raises(ValueError):
+        Loader().load_instance("neos-941sdfsdf262.mps.gz")
+
+
+def test_miplib_2010():
+    instance = Loader().load_instance("neos-941262.mps.gz")
+    assert isinstance(instance, scip.Model)
+
+
+def test_miplib_2003():
+    instance = Loader().load_instance("vpm2.mps.gz")
+    assert isinstance(instance, scip.Model)