Skip to content

Commit

Permalink
updated some linting
Browse files Browse the repository at this point in the history
  • Loading branch information
gbomarito committed Sep 18, 2024
1 parent 2b3c304 commit f144305
Show file tree
Hide file tree
Showing 8 changed files with 629 additions and 326 deletions.
771 changes: 504 additions & 267 deletions .pylintrc

Large diffs are not rendered by default.

32 changes: 26 additions & 6 deletions bingo/chromosomes/multiple_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
This file contains several classes that are used for chromosomes
that contains a list of genetic information.
"""

import numpy as np

from .chromosome import Chromosome
Expand All @@ -13,7 +14,7 @@


class MultipleValueChromosome(Chromosome):
""" Multiple value individual
"""Multiple value individual
The constructor for a chromosome that holds a list
of values as opposed to a single value.
Expand All @@ -29,6 +30,7 @@ class MultipleValueChromosome(Chromosome):
the genetic information of the individual
"""

def __init__(self, values):
super().__init__()
self.values = values
Expand All @@ -50,9 +52,18 @@ def distance(self, other):
dist : float
The distance between self and another chromosome
"""
dist = sum([v1 != v2 for v1, v2 in zip(self.values, other.values)])
dist = sum(v1 != v2 for v1, v2 in zip(self.values, other.values))
return dist

def get_number_local_optimization_params(self):
raise NotImplementedError

def needs_local_optimization(self):
raise NotImplementedError

def set_local_optimization_params(self, params):
raise NotImplementedError


class MultipleValueChromosomeGenerator(Generator):
"""Generation of a population of Multi-Value chromosomes
Expand All @@ -65,6 +76,7 @@ class MultipleValueChromosomeGenerator(Generator):
values_per_chromosome : int
the number of values that each chromosome will hold
"""

@argument_validation(values_per_chromosome={">=": 0})
def __init__(self, random_value_function, values_per_chromosome):
super().__init__()
Expand Down Expand Up @@ -106,10 +118,12 @@ class SinglePointMutation(Mutation):
last_mutation_type : str
the last mutation type that happened (or None)
"""

def __init__(self, mutation_function):
super().__init__()
self.types = ["single_point"]
self._mutation_function = mutation_function
self.last_mutation_type = None

def __call__(self, parent):
"""Performs single-point mutation using the user-defined
Expand Down Expand Up @@ -149,10 +163,12 @@ class SinglePointCrossover(Crossover):
the crossover type (or None) that happened to create the first child
and second child, respectively
"""

def __init__(self):
super().__init__()
self.types = ["single_point"]
self._crossover_point = 0
self.last_crossover_types = (None, None)

def __call__(self, parent_1, parent_2):
"""Performs single-point crossover of two parent chromosomes
Expand All @@ -174,10 +190,14 @@ def __call__(self, parent_1, parent_2):
child_1.fit_set = False
child_2.fit_set = False
self._crossover_point = np.random.randint(len(parent_1.values))
child_1.values = parent_1.values[:self._crossover_point] \
+ parent_2.values[self._crossover_point:]
child_2.values = parent_2.values[:self._crossover_point] \
+ parent_1.values[self._crossover_point:]
child_1.values = (
parent_1.values[: self._crossover_point]
+ parent_2.values[self._crossover_point :]
)
child_2.values = (
parent_2.values[: self._crossover_point]
+ parent_1.values[self._crossover_point :]
)
if parent_1.genetic_age > parent_2.genetic_age:
age = parent_1.genetic_age
else:
Expand Down
11 changes: 6 additions & 5 deletions bingo/evaluation/evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
This module defines the basic form of the evaluation phase of bingo
evolutionary algorithms.
"""

from multiprocessing import Pool


Expand Down Expand Up @@ -36,6 +37,7 @@ class Evaluation:
eval_count : int
the number of fitness function evaluations that have occurred
"""

def __init__(self, fitness_function, redundant=False, multiprocess=False):
self.fitness_function = fitness_function
self._redundant = redundant
Expand All @@ -51,7 +53,7 @@ def eval_count(self, value):
self.fitness_function.eval_count = value

def __call__(self, population):
"""Evaluates the fitness of an individual
"""Evaluates the fitness of a population
Parameters
----------
Expand All @@ -69,16 +71,15 @@ def _serial_eval(self, population):
indv.fitness = self.fitness_function(indv)

def _multiprocess_eval(self, population):
num_procs = self._multiprocess if isinstance(self._multiprocess, int) \
else None
num_procs = self._multiprocess if isinstance(self._multiprocess, int) else None

with Pool(processes=num_procs) as pool:
results = []
for i, indv in enumerate(population):
if self._redundant or not indv.fit_set:
results.append(
pool.apply_async(_fitness_job,
(indv, self.fitness_function, i)))
pool.apply_async(_fitness_job, (indv, self.fitness_function, i))
)

for res in results:
indv, extra_evals, i = res.get()
Expand Down
6 changes: 3 additions & 3 deletions bingo/evaluation/fitness_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@


# Fitness metric functions, outside of FitnessFunction for use in GradientMixin
def mean_absolute_error(vector, individual=None):
def mean_absolute_error(vector, individual=None): # pylint: disable=unused-argument
"""Calculate the mean absolute error of an error vector"""
return np.mean(np.abs(vector))


def root_mean_squared_error(vector, individual=None):
def root_mean_squared_error(vector, individual=None): # pylint: disable=unused-argument
"""Calculate the root mean squared error of an error vector"""
return np.sqrt(np.mean(np.square(vector)))


def mean_squared_error(vector, individual=None):
def mean_squared_error(vector, individual=None): # pylint: disable=unused-argument
"""Calculate the mean squared error of an error vector"""
return np.mean(np.square(vector))

Expand Down
64 changes: 58 additions & 6 deletions bingo/evaluation/random_subset_evaluation.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
"""Evaluation phase with random subsampling
In cases where evaluation is expensive it is sometimes useful to evaluate
fitness only on a subset of the underlying training data. This class does this
by randomly selecting subsets of the data for fitness evaluation. The random
subset selection occurs each time this evaluation phase is called.
"""

from copy import deepcopy
import numpy as np

Expand All @@ -6,22 +14,66 @@


class RandomSubsetEvaluation(Evaluation):
@argument_validation(subset_size={">=": 1},)
"""Phase which evaluates population using random subsets of training data
A class for fitness evaluation of populations using random subsamples of
training data. A random subset of the training data is chosen each call.
All individuals in the population are then evaluated with a fitness
function using that same random subset.
Parameters
----------
fitness_function : FitnessFunction
The function class that is used to calculate fitnesses of individuals
in the population.
subset_size : int
The size of the subset of training data that will be used for fitness
evaluation.
redundant : bool
Whether to re-evaluate individuals that have been evaluated previously.
Default True. Using False may lead to unexpected results where
individuals are compared on disimilar subsets of the training data.
multiprocess : int or bool
Number of processes to use in parallel evaluation
or False for serial evaluation. If using multiple processes,
individuals and fitness functions need to be pickle-able.
Default False.
Attributes
----------
fitness_function : FitnessFunction
The function class that is used to calculate fitnesses of individuals
in the population.
eval_count : int
the number of fitness function evaluations that have occurred
"""

@argument_validation(
subset_size={">=": 1},
)
def __init__(
self,
fitness_function,
subset_size,
redundant=False,
redundant=True,
multiprocess=False,
):
super().__init__(fitness_function, redundant, multiprocess)
self._subset_size = subset_size
self._full_training_data = deepcopy(fitness_function.training_data)

def __call__(self, individual):
def __call__(self, population):
"""Evaluates the fitness of a population using random subsampling
Parameters
----------
population : list of chromosomes
population for which fitness should be calculated
"""
subset = np.random.choice(
len(self._full_training_data), self._subset_size, replace=False,
len(self._full_training_data),
self._subset_size,
replace=False,
)
self.fitness_function.training_data = self._full_training_data[subset]
super().__call__(individual)

super().__call__(population)
19 changes: 11 additions & 8 deletions bingo/evolutionary_optimizers/fitness_predictor_island.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
predictors." IEEE Transactions on Evolutionary Computation 12.6 (2008):
736-749.
"""

import logging
from copy import copy, deepcopy
import numpy as np
Expand Down Expand Up @@ -104,7 +105,9 @@ def __init__(
hall_of_fame=None,
test_function=None,
):
super().__init__(evolution_algorithm, generator, population_size, None, test_function)
super().__init__(
evolution_algorithm, generator, population_size, None, test_function
)

self._hof_w_true_fitness = hall_of_fame
self._hof_w_predicted_fitness = deepcopy(hall_of_fame)
Expand Down Expand Up @@ -250,18 +253,18 @@ def _calculate_predictor_variance_of(self, individual):

def _get_predictor_computation_ratio(self):
predictor_expense = self._predictor_fitness_function.point_eval_count
island_expense = (
self._fitness_function.eval_count * self._predictor_size
)
island_expense = self._fitness_function.eval_count * self._predictor_size
return predictor_expense / (predictor_expense + island_expense)

def _get_potential_hof_members(self):
self._hof_w_predicted_fitness.update(self.population)
potential_members = []
for indv_w_ped_fitness in self._hof_w_predicted_fitness:
indv_w_true_fitness = deepcopy(indv_w_ped_fitness)
indv_w_true_fitness.fitness = self._predictor_fitness_function.get_true_fitness_for_trainer(
indv_w_true_fitness
indv_w_true_fitness.fitness = (
self._predictor_fitness_function.get_true_fitness_for_trainer(
indv_w_true_fitness
)
)
potential_members.append(indv_w_true_fitness)
return potential_members
Expand All @@ -278,7 +281,7 @@ def get_best_individual(self):
The chromosomes with the lowest fitness value
"""
best_indv = super().get_best_individual().copy()
best_indv.fitness = self._predictor_fitness_function.get_true_fitness_for_trainer(
best_indv
best_indv.fitness = (
self._predictor_fitness_function.get_true_fitness_for_trainer(best_indv)
)
return best_indv
13 changes: 7 additions & 6 deletions bingo/evolutionary_optimizers/serial_archipelago.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
This module defines the Archipelago data structure that runs serially on
one processor.
"""

import copy
import logging
import numpy as np
Expand Down Expand Up @@ -37,7 +38,9 @@ class SerialArchipelago(Archipelago):
An object containing the best individuals seen in the archipelago
"""

def __init__(self, template_island, num_islands=2, hall_of_fame=None, test_function=None):
def __init__(
self, template_island, num_islands=2, hall_of_fame=None, test_function=None
):
super().__init__(num_islands, hall_of_fame, test_function)
self._template_island = template_island
self.islands = self._generate_islands(template_island, num_islands)
Expand Down Expand Up @@ -79,19 +82,17 @@ def get_best_individual(self):
return list_of_best_indvs[0]

def get_fitness_evaluation_count(self):
""" Gets the number of fitness evaluations performed
"""Gets the number of fitness evaluations performed
Returns
-------
int :
number of fitness evaluations
"""
return sum(
[island.get_fitness_evaluation_count() for island in self.islands]
)
return sum(island.get_fitness_evaluation_count() for island in self.islands)

def get_ea_diagnostic_info(self):
""" Gets diagnostic info from the evolutionary algorithm(s)
"""Gets diagnostic info from the evolutionary algorithm(s)
Returns
-------
Expand Down
Loading

0 comments on commit f144305

Please sign in to comment.