Selectors
*********


Abstract Base Selector
======================

class BaseSelector(*avail_opts, allow_spawn=None)

   Base selector from which all selectors must inherit to be
   compatible with GloMPO. Selectors are classes which return an
   optimizer and its configuration when asked by the manager. This
   selection will then be used to start a new optimizer. The full
   manager is supplied to the selector allowing sophisticated
   decisions to be designed.

   Parameters:
   "*avail_opts"
      A set of optimizers available to the minimization. Elements may
      be:

      1. Subclasses or instances of "BaseOptimizer".

      2. Tuples of:

         1. "BaseOptimizer" subclasses (not instances);

         2. Dictionary of kwargs sent to "BaseOptimizer.__init__", or
            "None";

   allow_spawn
      Optional function sent to the selector which is called with the
      manager object as argument. If it returns "False" the manager
      will no longer spawn optimizers. See Spawn Control.

   Examples:
   >>> DummySelector(OptimizerA(), OptimizerB(setting_a=7))
   >>> DummySelector((OptimizerA, None), (OptimizerB, {'setting_a': 7}))

   Both of the above are equivalent. The "DummySelector" above may
   choose from two optimizers ("OptimizerA" or "OptimizerB").
   "OptimizerA" has no special configuration settings. "OptimizerB" is
   configured with "setting_a = 7" at initialisation.

   >>> DummySelector(OptimizerA, allow_spawn=IterSpawnStop(50_000))

   In this case the selector will only spawn "OptimizerA" optimizers
   but not allow any spawning after 50000 function evaluations.

   Attributes:
   allow_spawn : "BaseController"
      Function used to control if a new optimizer should be allowed to
      be created.

   avail_opts : List[Tuple[Type[BaseOptimizer], Optional[Dict[str,
   Any]]]]
      Set of optimizers and configuration settings available to the
      optimizer.

   logger : logging.Logger
      "logging.Logger" instance into which status messages may be
      added.

   abstract select_optimizer(manager, slots_available)

      Selects an optimizer to start from the available options.

      Parameters:
      manager
         "GloMPOManager" instance managing the optimization from which
         various attributes can be read.

      slots_available
         Number of processes/threads the manager is allowed to start
         according to "GloMPOManager.max_jobs" and the number of
         existing threads. GloMPO assumes that the selector will use
         this parameter to return an optimizer which requires fewer
         processes/threads than "slots_available". If this is not
         possible then "None" is returned.

      Returns:
      Union[Tuple[Type[BaseOptimizer], Dict[str, Any]], None, bool]
         Optimizer class and configuration parameters: Tuple of
         optimizer class and dictionary of initialisation parameters.
         Manager will use this to initialise and start a new
         optimizer.

         "None" is returned when no available optimizer configurations
         can satisfy the number of worker slots available.

         "False" is a special return which flags that the manager must
         never try and start another optimizer for the remainder of
         the optimization.


Spawn Control
=============

As seen above, spawning new optimizers can be stopped without shutting
down the entire optimization. This can be used to make sure that
functioning optimizers are given time to explore, and function
evaluations are not wasted on new optimizers towards the end of an
optimization when they will be unlikely to have enough time to
develop. GloMPO comes bundled with a couple of simple convenient
controllers.

class BaseController

   Conditions to stop new optimizers being started even if there are
   available worker slots.

   abstract __call__(mng)

      Returns "True" if the Selector may start a new optimizer,
      "False" otherwise. Evaluated everytime the selector is called.

class IterSpawnStop(max_calls)

   Controls spawning based on the number of function calls used thus
   far.

   Parameters:
   max_calls
      Maximum number of function calls allowed, after which no more
      optimizers will be started.

class NOptimizersSpawnStop(max_opts)

   Controls spawning based on the number of optimizers used thus far.

   Parameters:
   max_opts
      Maximum number of optimizers allowed, after which no more
      optimizers will be started.


Included Selectors
==================

For convenience, GloMPO comes bundled with several simple selectors
already included.

class ChainSelector(*avail_opts, fcall_thresholds, allow_spawn=None)

   Bases: "BaseSelector"

   Selects the type of optimizer to start based on the number of
   function evaluations already used. Designed to start different
   types of optimizers at different stages of the optimization.
   Selects sequentially from the list of available optimizers based on
   the number of function evaluations used.

   Parameters:
   "*avail_opts"
      See "BaseSelector".

   fcall_thresholds
      A list of length "n-1", where "n" is the length of "avail_opts".

      Each element indicates the function evaluation point at which
      the selector switches to the next type of optimizer in
      "avail_opts".

   allow_spawn
      See "BaseSelector".

   Examples:
   >>> ChainSelector(OptimizerA, OptimizerB, fcall_thresholds=[1000])

   In this case "OptimizerA" instances will be started in the first
   1000 iterations and "OptimizerB" instances will be started
   thereafter.

class CycleSelector(*avail_opts, allow_spawn=None)

   Bases: "BaseSelector"

   Cycles through the list of available optimizers. Iterates through
   the list of available optimizers everytime "select_optimizer()" is
   called. When the last element is reached, the selector loops back
   to the beginning.

   Examples:
   >>> selector = CycleSelector(OptimizerA, OptimizerB, OptimizerC)
   >>> for i in range(5):
   ...     selector.select_optimizer(manager, log, 1)
   OptimizerA
   OptimizerB
   OptimizerC
   OptimizerA
   OptimizerB

class RandomSelector(*avail_opts, allow_spawn=None)

   Bases: "BaseSelector"

   Randomly selects an optimizer from the available options.
