Repository: ICB-DCM/pyABC

Issue:
Implement ListTemperature
To allow a list of temperatures, similar to ListEpsilon.

Discussion:

Patch:
diff --git a/pyabc/__init__.py b/pyabc/__init__.py
index 66155b8..688e949 100644
--- a/pyabc/__init__.py
+++ b/pyabc/__init__.py
@@ -46,6 +46,8 @@ from .epsilon import (
     QuantileEpsilon,
     MedianEpsilon,
     ListEpsilon,
+    TemperatureBase,
+    ListTemperature,
     Temperature,
     TemperatureScheme,
     AcceptanceRateScheme,
@@ -117,6 +119,8 @@ __all__ = [
     "ListEpsilon",
     "QuantileEpsilon",
     "MedianEpsilon",
+    "TemperatureBase",
+    "ListTemperature",
     "Temperature",
     "TemperatureScheme",
     "AcceptanceRateScheme",
diff --git a/pyabc/epsilon/__init__.py b/pyabc/epsilon/__init__.py
index f77153b..d50d366 100644
--- a/pyabc/epsilon/__init__.py
+++ b/pyabc/epsilon/__init__.py
@@ -19,6 +19,8 @@ from .epsilon import (
     MedianEpsilon,
 )
 from .temperature import (
+    TemperatureBase,
+    ListTemperature,
     Temperature,
     TemperatureScheme,
     AcceptanceRateScheme,
@@ -41,6 +43,8 @@ __all__ = [
     'QuantileEpsilon',
     'MedianEpsilon',
     # temperature
+    'TemperatureBase',
+    'ListTemperature',
     'Temperature',
     'TemperatureScheme',
     'AcceptanceRateScheme',
diff --git a/pyabc/epsilon/temperature.py b/pyabc/epsilon/temperature.py
index b29d28d..f71b785 100644
--- a/pyabc/epsilon/temperature.py
+++ b/pyabc/epsilon/temperature.py
@@ -13,11 +13,42 @@ from ..storage import save_dict_to_json
 logger = logging.getLogger("Epsilon")
 
 
-class Temperature(Epsilon):
+class TemperatureBase(Epsilon):
     """
     A temperature scheme handles the decrease of the temperatures employed
     by a :class:`pyabc.acceptor.StochasticAcceptor` over time.
 
+    This class is not functional on its own, its derivatives must be used.
+    """
+
+
+class ListTemperature(TemperatureBase):
+    """
+    Pass a list of temperature values to use successively.
+
+    Parameters
+    ----------
+    values:
+        The array of temperatures to use successively.
+        For exact inference, finish with 1.
+    """
+
+    def __init__(self, values: List[float]):
+        self.values = values
+
+    def __call__(self,
+                 t: int) -> float:
+        return self.values[t]
+
+
+class Temperature(TemperatureBase):
+    """
+    This class implements a highly adaptive and configurable temperature
+    scheme. Via the argument `schemes`, arbitrary temperature schemes can be
+    passed to calculate the next generation's temperature, via `aggregate_fun`
+    one can define how to combine multiple guesses, via `initial_temperature`
+    the initial temperature can be set.
+
     Parameters
     ----------
     schemes: Union[Callable, List[Callable]], optional
diff --git a/pyabc/smc.py b/pyabc/smc.py
index 4a35854..e381262 100644
--- a/pyabc/smc.py
+++ b/pyabc/smc.py
@@ -18,7 +18,7 @@ from typing import Union
 from .acceptor import (Acceptor, UniformAcceptor, SimpleFunctionAcceptor,
                        StochasticAcceptor)
 from .distance import Distance, PNormDistance, to_distance, StochasticKernel
-from .epsilon import Epsilon, MedianEpsilon, Temperature
+from .epsilon import Epsilon, MedianEpsilon, TemperatureBase
 from .model import Model, SimpleModel
 from .platform_factory import DefaultSampler
 from .population import Particle, Population
@@ -229,13 +229,14 @@ class ABCSMC:
     def _sanity_check(self):
         # check stochastic setting
         stochastics = [isinstance(self.acceptor, StochasticAcceptor),
-                       isinstance(self.eps, Temperature),
+                       isinstance(self.eps, TemperatureBase),
                        isinstance(self.distance_function, StochasticKernel)]
         # check if usage is consistent
         if not all(stochastics) and any(stochastics):
             raise ValueError(
                 "Please only use acceptor.StochasticAcceptor, "
-                "epsilon.Temperature and distance.StochasticKernel together.")
+                "epsilon.TemperatureBase and distance.StochasticKernel "
+                "together.")
 
     def __getstate__(self):
         state_red_dict = self.__dict__.copy()
@@ -838,7 +839,7 @@ class ABCSMC:
         """
         # handle arguments
         if minimum_epsilon is None:
-            if isinstance(self.eps, Temperature):
+            if isinstance(self.eps, TemperatureBase):
                 minimum_epsilon = 1.0
             else:
                 minimum_epsilon = 0.0


Test patch:
diff --git a/test/test_epsilon.py b/test/test_epsilon.py
index 1d47580..a48ccac 100644
--- a/test/test_epsilon.py
+++ b/test/test_epsilon.py
@@ -53,6 +53,15 @@ def test_medianepsilon():
     assert np.isclose(eps.alpha, 0.5)
 
 
+def test_listtemperature():
+    eps = pyabc.ListTemperature(values=[10, 5, 1.5])
+
+    # might be useful to test integration, but for the moment
+    # standalone tests may suffice
+    assert eps(0) == 10
+    assert eps(2) == 1.5
+
+
 def test_temperature():
     acceptor_config = {
         'pdf_norm': 5,