Example #1
0
    def test_add_to_initial_population_successful(self):
        class SpyFitnessFunc:
            def __init__(self):
                self.fitness_func_executions = 0

            def fitness_func(self, bitstring):
                self.fitness_func_executions += 1
                return 69.0

        unused_spy_fitness_function_holder = SpyFitnessFunc()
        genome_factory = PassThroughGenomeFactory(
            Genome.new_default_genome(
                (5, ), unused_spy_fitness_function_holder.fitness_func))
        annealing_schedule = PassThroughAnnealingSchedule(0, True)
        optimizer_builder = BasicAnnealerOptimizerBuilder(
            (5, ), NumpyRNG(), genome_factory, annealing_schedule,
            unused_spy_fitness_function_holder.fitness_func)

        spy_fitness_function_holder = SpyFitnessFunc()
        population_genome = Genome(spy_fitness_function_holder.fitness_func,
                                   (0, 0, 0, 0, 0))

        optimizer = optimizer_builder \
            .add_to_initial_population(population_genome) \
            .build()

        self.assertAlmostEqual(optimizer.best_genome.fitness, 69.0)
        self.assertEqual(spy_fitness_function_holder.fitness_func_executions,
                         1)
        self.assertIsInstance(optimizer, BasicAnnealingOptimizer)
Example #2
0
    def test_multiple_population_add(self):
        class SpyFitnessFunc:
            def __init__(self):
                self.fitness_func_executions = 0

            def fitness_func(self, bitstring):
                self.fitness_func_executions += 1
                return 69.0

        unused_spy_fitness_function_holder = SpyFitnessFunc()
        genome_factory = PassThroughGenomeFactory(
            Genome.new_default_genome(
                (5, ), unused_spy_fitness_function_holder.fitness_func))
        convergence_criterion = PassThroughConvergenceCriterion(True)
        optimizer_builder = BasicOptimizerBuilder(
            (5, ), NumpyRNG(), genome_factory, convergence_criterion,
            unused_spy_fitness_function_holder.fitness_func)

        spy_fitness_function_holder = SpyFitnessFunc()
        population_genome = Genome(spy_fitness_function_holder.fitness_func,
                                   (0, 0, 0, 0, 0))

        optimizer = optimizer_builder \
            .add_to_initial_population(population_genome) \
            .build()

        self.assertAlmostEqual(optimizer.best_genome.fitness, 69.0)
        self.assertEqual(spy_fitness_function_holder.fitness_func_executions,
                         1)
        self.assertIsInstance(optimizer, BasicOptimizer)

        with self.assertRaises(InitialPopulationUndefinedException):
            optimizer_builder.clear().build()
Example #3
0
    def test_convergence(self):
        def fitness_func_zero(bitstring):
            return 0

        initial_candidate = Genome(fitness_func_zero, (0,))

        convergence_criterion = PassThroughConvergenceCriterion(True)
        genome_builder = PassThroughGenomeFactory(Genome(fitness_func_zero, (1,)))
        optimizer = BasicOptimizer(initial_candidate, genome_builder, convergence_criterion)

        self.assertFalse(optimizer.converged)
        optimizer.next()
        self.assertTrue(optimizer.converged)
Example #4
0
    def test_add_to_initial_population_returns_self(self):
        def fitness_func(bitstring):
            self.fail()
            return 0.0

        genome_factory = PassThroughGenomeFactory(
            Genome.new_default_genome((5, ), fitness_func))
        annealing_schedule = PassThroughAnnealingSchedule(0, True)
        optimizer_builder = BasicAnnealerOptimizerBuilder(
            (5, ), NumpyRNG(), genome_factory, annealing_schedule,
            fitness_func)

        returned_object = optimizer_builder.add_to_initial_population(
            Genome.new_default_genome((5, ), fitness_func))
        self.assertEqual(optimizer_builder, returned_object)
Example #5
0
    def test_add_to_initial_population_returns_self(self):
        def fitness_func(bitstring):
            self.fail()
            return 0.0

        genome_factory = PassThroughGenomeFactory(
            Genome.new_default_genome((5, ), fitness_func))
        convergence_criterion = PassThroughConvergenceCriterion(True)
        optimizer_builder = BasicOptimizerBuilder(
            (5, ), NumpyRNG(), genome_factory, convergence_criterion,
            fitness_func)

        returned_object = optimizer_builder.add_to_initial_population(
            Genome.new_default_genome((5, ), fitness_func))
        self.assertEqual(optimizer_builder, returned_object)
Example #6
0
    def test_next_generation_improvement(self):
        def fitness_func_zero(bitstring):
            return 0

        def fitness_func_one(bitstring):
            return 1

        initial_candidate = Genome(fitness_func_zero, (0,))

        convergence_criterion = PassThroughConvergenceCriterion(True)
        genome_builder = PassThroughGenomeFactory(Genome(fitness_func_one, (1,)))
        optimizer = BasicOptimizer(initial_candidate, genome_builder, convergence_criterion)

        optimizer.next()

        self.assertEqual(1, optimizer.best_genome.fitness)
Example #7
0
    def build(self, prior_genomes: List[Genome]) -> Genome:
        """ Builds a new Genome from a list of priors

        :param prior_genomes: list of prior Genomes
        :return: a new Genome object
        """
        bitstring = self._rng.random_int_array(0, 1, self._dimensions)
        return Genome(self._fitness_func, bitstring, *self._args, **self._kwargs)
Example #8
0
def new_simulated_annealer(
        dimensions: Tuple,
        max_neighbor_distance: int,
        initial_temperature: float,
        minimum_temperature: float,
        degradation_multiplier: float,
        fitness_func: Callable[..., float],
        *args,
        **kwargs) -> AbstractOptimizer:
    """
    Creates a new optimizer that optimizes by simulated annealing using a default temperature schedule.

    :param dimensions: dimension of bitstrings passed into fitness_func
    :param max_neighbor_distance: Manhattan distance allowed between neighbors
    :param initial_temperature: starting temperature
    :param minimum_temperature: minimum temperature before convergence
    :param degradation_multiplier: temperature will be multiplied by this every iteration
    :param fitness_func: function to optimize (accepts a bitstring)
    :param args: will be passed into fitness_func
    :param kwargs: will be passed into fitness_func
    :return: a new optimizer
    """
    random = NumpyRNG()

    neighbor_genome_factory = \
        RandomNeighborGenomeFactory(
            dimensions,
            random,
            max_neighbor_distance,
            fitness_func,
            *args,
            **kwargs)

    annealing_schedule = \
        ExponentialAnnealingSchedule(
            initial_temperature,
            minimum_temperature,
            degradation_multiplier)

    initial_candidate = \
        Genome.new_default_genome(
            dimensions,
            fitness_func,
            *args,
            **kwargs)

    initial_candidate.run()

    return BasicAnnealingOptimizer(
        initial_candidate,
        neighbor_genome_factory,
        annealing_schedule,
        random)
Example #9
0
    def test_build_raises_exception_with_no_population(self):
        def fitness_func(bitstring):
            self.fail()
            return 0.0

        genome_factory = PassThroughGenomeFactory(
            Genome.new_default_genome((5, ), fitness_func))
        annealing_schedule = PassThroughAnnealingSchedule(0, True)
        optimizer_builder = BasicAnnealerOptimizerBuilder(
            (5, ), NumpyRNG(), genome_factory, annealing_schedule,
            fitness_func)

        with self.assertRaises(InitialPopulationUndefinedException):
            optimizer_builder.build()
Example #10
0
    def test_build_raises_exception_with_no_population(self):
        def fitness_func(bitstring):
            self.fail()
            return 0.0

        genome_factory = PassThroughGenomeFactory(
            Genome.new_default_genome((5, ), fitness_func))
        convergence_criterion = PassThroughConvergenceCriterion(True)
        optimizer_builder = BasicOptimizerBuilder(
            (5, ), NumpyRNG(), genome_factory, convergence_criterion,
            fitness_func)

        with self.assertRaises(InitialPopulationUndefinedException):
            optimizer_builder.build()
Example #11
0
    def test_add_to_initial_population_from_factory_successful(self):
        def fitness_func(bitstring):
            return 69.0

        genome_factory = PassThroughGenomeFactory(
            Genome.new_default_genome((5, ), fitness_func))
        annealing_schedule = PassThroughAnnealingSchedule(0, True)
        optimizer_builder = BasicAnnealerOptimizerBuilder(
            (5, ), NumpyRNG(), genome_factory, annealing_schedule,
            fitness_func)

        optimizer = optimizer_builder \
            .add_to_initial_population_from_factory(genome_factory, 1) \
            .build()

        self.assertAlmostEqual(optimizer.best_genome.fitness, 69.0)
        self.assertIsInstance(optimizer, BasicAnnealingOptimizer)
Example #12
0
    def add_to_initial_population_from_factory(
            self, genome_factory: AbstractGenomeFactory,
            n: int) -> AbstractOptimizerBuilder:
        """
        Adds a given number of Genomes to the initial population of this optimizer from a factory

        :param genome_factory: the factory that will generate the Genome
        :param n: number of instances to add
        :return: self
        """
        base_genome = Genome.new_default_genome(genome_factory.dimensions,
                                                self._fitness_func,
                                                *self._args, **self._kwargs)
        self._population += [
            genome_factory.build([base_genome]) for _ in range(n)
        ]
        return self
Example #13
0
    def test_add_to_initial_population_from_factory_successful(self):
        def fitness_func(bitstring):
            return 69.0

        genome_factory = PassThroughGenomeFactory(
            Genome.new_default_genome((5, ), fitness_func))
        convergence_criterion = PassThroughConvergenceCriterion(True)
        optimizer_builder = BasicOptimizerBuilder(
            (5, ), NumpyRNG(), genome_factory, convergence_criterion,
            fitness_func)

        optimizer = optimizer_builder \
            .add_to_initial_population_from_factory(genome_factory, 1) \
            .build()

        self.assertAlmostEqual(optimizer.best_genome.fitness, 69.0)
        self.assertIsInstance(optimizer, BasicOptimizer)
Example #14
0
def new_hill_climber(
        dimensions: Tuple,
        convergence_iterations: int,
        epsilon: float,
        fitness_func: Callable[..., float],
        *args,
        **kwargs) -> AbstractOptimizer:
    """
    Builds a new optimizer that generates and evaluates a candidate, finds a neighbor of this candidate,
    and determines if the neighbor is more suitable than the original candidate.

    :param dimensions: dimension of bitstrings passed into fitness_func
    :param convergence_iterations: number candidates to evaluate without improvement before declaring convergence
    :param epsilon: minimum required improvement between candidates to continue
    :param fitness_func: function to optimize (accepts a bitstring)
    :param args: will be passed into fitness_func
    :param kwargs: will be passed into fitness_func
    :return: a new optimizer
    """
    random = NumpyRNG()

    neighbor_genome_factory = \
        RandomNeighborGenomeFactory(
            dimensions,
            random,
            1,
            fitness_func,
            *args,
            **kwargs)

    initial_candidate = \
        Genome.new_default_genome(
            dimensions,
            fitness_func,
            *args,
            **kwargs)

    initial_candidate.run()

    convergence_criterion = ConsecutiveNonImprovement(convergence_iterations, epsilon)

    return BasicOptimizer(
        initial_candidate,
        neighbor_genome_factory,
        convergence_criterion)
    def test_returns_best_model(self):
        class CustomRandom(AbstractRandomNumberGenerator):

            def random_int_array(self, minimum, maximum, shape):
                return [0]

            def random(self):
                return 0.0

        rng = CustomRandom()
        comparer = RouletteWheelComparer(rng)
        genomes = [Genome.new_default_genome((10-index,), lambda bitstring: len(bitstring)) for index in range(10)]

        for genome in genomes:
            genome.run()

        returned_model = comparer.compare(genomes)
        self.assertEqual(10, returned_model.fitness)