def test_Optimizer_get_fitnesses_with_fitness_func_side_effects(): """Fitness function modifying solution should not affect fitnesses. This could potentially be a problem when there are duplicate solutions. """ # Fitness function is weighted summation of bits solution_size = random.randint(1, 50) weights = numpy.random.random(solution_size) def fitness_func(solution): for i, val in enumerate(solution): solution[i] *= 2 return weights.dot(solution) # Test Optimizer._get_fitnesses problem = Problem(fitness_func) optimizer = optimize.Optimizer() # Use simple map of fitness function over solutions as oracle # Repeat to test cache for _ in range(100): # Create a random population, and compare values returned by _get_fitness to simple maps population = common.make_population(random.randint(1, 20), common.random_binary_solution, solution_size) solutions, fitnesses, finished = optimizer._get_fitnesses( problem, copy.deepcopy(population), pool=None) assert fitnesses == map(fitness_func, population) assert finished is False
def test_Optimizer_get_solution_key(): # Hashable optimizer = optimize.Optimizer() optimizer._get_solution_key('1') == '1' # Dict # NOTE: This requires special treatment, otherwise, # tuple(dict) will return a tuple of the KEYS only optimizer = optimize.Optimizer() optimizer._get_solution_key({'a': '1'}) == tuple([('a', '1')]) # Tupleable optimizer = optimize.Optimizer() optimizer._get_solution_key(['1']) == tuple(['1']) # Stringable optimizer = optimize.Optimizer() optimizer._get_solution_key([['1']]) == str([['1']])
def _check_get_fitnesses(fitness_func, decode_func, solution_size, fitness_func_returns_finished=False, optimizer=None, n_processes=0, **kwargs): """Assert that return values of Optimizer._get_fitnesses are correct.""" problem = Problem(fitness_func, decode_function=decode_func) if optimizer is None: optimizer = optimize.Optimizer() if n_processes > 0: pool = multiprocessing.Pool(processes=n_processes) else: pool = None # Use simple map of fitness function over solutions as oracle # Repeat to test cache for _ in range(100): # Create a random population, and compare values returned by _get_fitness to simple maps population = common.make_population(random.randint(1, 20), common.random_binary_solution, solution_size) solutions, fitnesses, finished = optimizer._get_fitnesses( problem, copy.deepcopy(population), pool=pool, **kwargs) # NOTE: _get_fitnesses will return None for solutions in cache, this is expected and ok assert False not in [ solution == expected for solution, expected in zip( solutions, map(decode_func, population)) if solution is not None ] if fitness_func_returns_finished is False: assert fitnesses == map(fitness_func, map(decode_func, population)) else: # Need to strip finished from fitness_func return values assert fitnesses == [ fitness_finished[0] for fitness_finished in map( fitness_func, map(decode_func, population)) ] assert finished is False
def test_Optimizer_encoded_cache_correct(): """Should map the correct key to fitness.""" optimizer = optimize.Optimizer() def fitness_func(solution): return solution[0] + 0.5 * solution[1] problem = Problem(fitness_func) # Test cache optimizer._get_fitnesses(problem, [[0, 0], [0, 1], [1, 0], [1, 1]], cache_encoded=True) assert optimizer._Optimizer__encoded_cache == { (0, 0): 0, (0, 1): 0.5, (1, 0): 1.0, (1, 1): 1.5 }
def test_Optimizer_solution_cache_correct(): """Should map the correct key to fitness.""" optimizer = optimize.Optimizer() def fitness_func(solution): return solution[0] + 0.5 * solution[1] def decode_func(encoded_solution): return (-encoded_solution[0], -encoded_solution[1]) problem = Problem(fitness_func, decode_function=decode_func) # Test cache optimizer._get_fitnesses(problem, [[0, 0], [0, 1], [1, 0], [1, 1]], cache_solution=True) assert optimizer._Optimizer__solution_cache == { (0, 0): 0, (0, -1): -0.5, (-1, 0): -1.0, (-1, -1): -1.5 }
def test_Optimizer_get_fitnesses_cache_encoded_False_cache_solution_True(): """Fitnesses should correspond to solutions.""" # Fitness function is weighted summation of bits solution_size = random.randint(1, 50) weights = numpy.random.random(solution_size) def fitness_func(solution): return weights.dot(solution) # Optimizer with disabled encoded cache optimizer = optimize.Optimizer() # Test Optimizer._get_fitnesses _check_get_fitnesses(fitness_func, lambda x: x, solution_size, optimizer=optimizer, cache_encoded=False, cache_solution=True) # Check caches as expected assert optimizer._Optimizer__encoded_cache == {} assert optimizer._Optimizer__solution_cache != {}
def test_Optimizer_get_fitnesses_unhashable_solution(): """Should not fail when solution cannot be hashed or cached.""" # Fitness function is weighted summation of bits solution_size = random.randint(1, 50) weights = numpy.random.random(solution_size) def fitness_func(solution): return weights.dot(solution.list) class ListWrapper(object): def __init__(self, list_): self.list = list_ def __eq__(self, other): return type(self) == type(other) and self.list == other.list def __hash__(self): raise NotImplementedError() def __str__(self): raise NotImplementedError() decode_weights = numpy.random.random(solution_size) def decode_func(encoded_solution): return ListWrapper(list(decode_weights * encoded_solution)) optimizer = optimize.Optimizer() # Test Optimizer._get_fitnesses _check_get_fitnesses(fitness_func, decode_func, solution_size, optimizer=optimizer, cache_solution=True) assert optimizer._Optimizer__solution_cache == {}