Source code for inspyred.ec.migrators

"""
    ==============================================
    :mod:`migrators` -- Solution migration methods
    ==============================================

    This module provides pre-defined migrators for evolutionary computations.

    All migrator functions have the following arguments:

    - *random* -- the random number generator object
    - *population* -- the population of Individuals
    - *args* -- a dictionary of keyword arguments

    Each migrator function returns the updated population.

    Migrator functions would typically be used for multi-population approaches,
    such as island-model evolutionary computations. They provide a means for
    individuals to be transferred from one population to another during the
    evolutionary process.

    .. Copyright 2012 Aaron Garrett

    .. Permission is hereby granted, free of charge, to any person obtaining a copy
       of this software and associated documentation files (the "Software"), to deal
       in the Software without restriction, including without limitation the rights
       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       copies of the Software, and to permit persons to whom the Software is
       furnished to do so, subject to the following conditions:

    .. The above copyright notice and this permission notice shall be included in
       all copies or substantial portions of the Software.

    .. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       THE SOFTWARE.

    .. module:: migrators
    .. moduleauthor:: Aaron Garrett <garrett@inspiredintelligence.io>
"""
import multiprocessing
import queue


[docs] def default_migration(random, population, args): """Do nothing. This function just returns the existing population with no changes. """ return population
[docs] class MultiprocessingMigrator(object): """Migrate among processes on the same machine. This callable class allows individuals to migrate from one process to another on the same machine. It maintains a queue of migrants whose maximum length can be fixed via the ``max_migrants`` parameter in the constructor. If the number of migrants in the queue reaches this value, new migrants are not added until earlier ones are consumed. The unreliability of a multiprocessing environment makes it difficult to provide guarantees. However, migrants are theoretically added and consumed at the same rate, so this value should determine the "freshness" of individuals, where smaller queue sizes provide more recency. An optional keyword argument in ``args`` requires the migrant to be evaluated by the current evolutionary computation before being inserted into the population. This can be important when different populations use different evaluation functions and you need to be able to compare "apples with apples," so to speak. The migration takes the current individual *I* out of the queue, if one exists. It then randomly chooses an individual *E* from the population to insert into the queue. Finally, if *I* exists, it replaces *E* in the population (re-evaluating fitness if necessary). Otherwise, *E* remains in the population and also exists in the queue as a migrant. Optional keyword arguments in args: - *evaluate_migrant* -- should new migrants be evaluated before adding them to the population (default False) """ def __init__(self, max_migrants=1): self.max_migrants = max_migrants self.migrants = multiprocessing.Queue(self.max_migrants) self._lock = multiprocessing.Lock() self.__name__ = self.__class__.__name__ def __call__(self, random, population, args): with self._lock: evaluate_migrant = args.setdefault('evaluate_migrant', False) migrant_index = random.randint(0, len(population) - 1) old_migrant = population[migrant_index] try: migrant = self.migrants.get(block=False) if evaluate_migrant: fit = args["_ec"].evaluator([migrant.candidate], args) migrant.fitness = fit[0] args["_ec"].num_evaluations += 1 population[migrant_index] = migrant except queue.Empty: pass try: self.migrants.put(old_migrant, block=False) except queue.Full: pass return population