lightweight_genetic_algorithm package

Submodules

lightweight_genetic_algorithm.algorithm module

class lightweight_genetic_algorithm.algorithm.GeneticAlgorithm(fitness_function, gene_ranges, fitness_function_args=(), number_of_genes=None, crossover_method='Either Or', mutation_mode=None, mutation_rate=None, measure=None, use_multiprocessing=False, ncpus=None, verbosity=1, selection_method='Diversity Enhanced', output_directory=None)[source]

Bases: object

A class to represent a Genetic Algorithm.

This class provides methods to perform optimization using genetic algorithms for both numerical and categorical parameters.

Parameters:
  • fitness_function (callable) – A function that calculates the fitness score of an individual.

  • gene_ranges (list) – A list specifying the possible values or ranges for each gene. For numerical genes, it is a list of tuples specifying the (min, max) range for each gene. For categorical genes, it is a simple list of possible categories.

  • fitness_function_args (tuple, optional) – Additional arguments to pass to the fitness_function (default is ()).

  • number_of_genes (int, optional) – The number of genes in each individual. If genes are numerical, it defaults to the length of gene_ranges. Must be specified if genes are categorical.

  • crossover_method (str, optional) – The method used for crossover. Options are “Between”, “Midpoint”, “Either Or”, or “None”. Default is “Either Or”.

  • mutation_mode (list of str, optional) – The mode used for mutation for each gene. Available options are: “additive”, “multiplicative”, “random”, “categorical”. Default is [“additive”]*number_of_genes for numerical genes and [“categorical”]*number_of_genes for categorical genes.

  • mutation_rate (float, optional) – The rate of mutation for each gene. Default is 1.0 / number_of_genes.

  • measure (str or callable, optional) – Defines the distance measure between two individuals for diversity. Options are “Hamming”, “Euclidean”, “Dynamic”, or a custom function. Default depends on gene type: “Hamming” for categorical genes, “Euclidean” for numerical genes.

  • use_multiprocessing (bool, optional) – Whether to use multiprocessing for fitness evaluations (default is False).

  • ncpus (int, optional) – The number of processes to use for multiprocessing (default is the number of CPUs minus one).

  • verbosity (int, optional) – The verbosity level. 0 = silent, 1 = normal output, 2 = detailed output (default is 1).

  • selection_method (str, optional) – The method used for selecting the best individuals for the next generation. Options are “Diversity Enhanced” or “Fitness Proportionate” (default is “Diversity Enhanced”).

  • output_directory (str, optional) –

    The directory to save output files (default is None). If specified, the algorithm saves the genes of the selected survivors in each generation to a file “<datetime>_survivors.npy” in the output directory. The average fitness and best fitness at each generation are saved to “<datetime>_fitness.txt”. A log file is saved to “log.txt” containing the output of the algorithm printed to the console.

    The “<datetime>_survivors.npy” file can be loaded using numpy.load(file, allow_pickle=True) to access the gene values of the individuals in each generation. The loaded array has shape (n_generations+1, population_size, number_of_genes) since the initial population is also saved.

fitness_function

The fitness function used to evaluate individuals.

Type:

callable

fitness_function_args

Additional arguments for the fitness function.

Type:

tuple

gene_ranges

The ranges or categories for each gene.

Type:

list

number_of_genes

The number of genes in each individual.

Type:

int

is_discrete

Indicates whether the genes are categorical.

Type:

bool

mutation_mode

Mutation modes for each gene.

Type:

list of str

mutation_rate

Mutation rate for each gene.

Type:

float

mutation

The mutation operator.

Type:

Mutation

crossover_method

The crossover operator or “none” if no crossover.

Type:

Crossover or str

survivor_selection

The survivor selection strategy.

Type:

SurvivorSelection

use_multiprocessing

Indicates whether multiprocessing is used.

Type:

bool

ncpus

Number of CPUs used if multiprocessing.

Type:

int

pool

The multiprocessing Pool object if multiprocessing is used.

Type:

multiprocessing.Pool or None

verbosity

Verbosity level.

Type:

int

output_directory

Directory for output files.

Type:

str

fitness_file

Path to the file where fitness values are saved (if output_directory is specified).

Type:

str

survivors_file

Path to the file where survivor gene values are saved (if output_directory is specified).

Type:

str

run(n_generations, population_size, init_genes=None, fitness_threshold=None, verbosity=1)[source]

Runs the genetic algorithm and returns the population at each generation.

run_light(n_generations, population_size, init_genes=None, fitness_threshold=None, verbosity=1)[source]

Runs the genetic algorithm and returns the gene values at each generation.

create_initial_population(n, init_gene_values=None)[source]

Creates the initial population of individuals.

Parameters:
  • n (int) – The number of individuals in the population.

  • init_gene_values (list, optional) – Initial gene values to seed the population. If None, the population is initialized randomly.

Returns:

The initial population of individuals.

Return type:

list of Individual

evaluate_fitness(genes)[source]

Evaluates the fitness of a set of genes using the fitness function.

Parameters:

genes (list) – The genes to evaluate.

Returns:

The fitness value of the genes.

Return type:

float

log(message, level=1)[source]

Logs a message to the console and, if specified, to the output directory log file.

Parameters:
  • message (str) – The message to log.

  • level (int, optional) – The level of verbosity required to print the message (default is 1).

run(n_generations, population_size, init_genes=None, fitness_threshold=None, verbosity=1)[source]

Runs the genetic algorithm for a specified number of generations.

Parameters:
  • n_generations (int) – The number of generations to run the genetic algorithm.

  • population_size (int) – The number of individuals in the population.

  • init_genes (list, optional) – Initial gene values to seed the population. If None, the population is initialized randomly.

  • fitness_threshold (float, optional) – The fitness threshold to stop the algorithm early. If None, the algorithm runs for n_generations.

  • verbosity (int, optional) – The verbosity level for printing messages. 0 = silent, 1 = normal output, 2 = detailed output (default is 1).

Returns:

A list containing the population at each generation. Each population is a list of Individual objects.

Return type:

list of list of Individual

run_light(n_generations, population_size, init_genes=None, fitness_threshold=None, verbosity=1)[source]

Runs the genetic algorithm and returns only the gene values.

Parameters:
  • n_generations (int) – The number of generations to run the genetic algorithm.

  • population_size (int) – The number of individuals in the population.

  • init_genes (list, optional) – Initial gene values to seed the population. If None, the population is initialized randomly.

  • fitness_threshold (float, optional) – The fitness threshold to stop the algorithm early. If None, the algorithm runs for n_generations.

  • verbosity (int, optional) – The verbosity level for printing messages. 0 = silent, 1 = normal output, 2 = detailed output (default is 1).

Returns:

A list containing the gene values of the population at each generation.

Return type:

list of list

setup_output_directory()[source]

Sets up the output directory for saving logs and output files.

start_pool()[source]

Starts the multiprocessing Pool if multiprocessing is enabled.

stop_pool()[source]

Closes the multiprocessing Pool if it is open.

lightweight_genetic_algorithm.crossover module

class lightweight_genetic_algorithm.crossover.Crossover[source]

Bases: object

This is a base class for all crossover methods. Crossover methods take the lists of genes of the parents as input.

crossover(parent1_genes, parent2_genes)[source]

Perform crossover between two parents.

Parameters:
  • parent1_genes (List[Gene]) – The first parent’s genes.

  • parent2_genes (List[Gene]) – The second parent’s genes.

Returns:

The child genes resulting from crossover.

Return type:

List[Gene]

class lightweight_genetic_algorithm.crossover.CrossoverBetween[source]

Bases: Crossover

Implements a ‘between’ crossover method where each child’s gene is a random value between the corresponding genes of the two parents.

Each gene in the child is generated by uniformly sampling a value between the values of the corresponding genes in the parents.

Note

  • The genes must have a ‘crossover_methods’ attribute that includes ‘between’.

  • The genes must have ‘value’, ‘low’, and ‘high’ attributes.

crossover(parent1_genes, parent2_genes)[source]

Perform ‘between’ crossover between two parents.

Parameters:
  • parent1_genes (List[NumericGene]) – The genes from the first parent.

  • parent2_genes (List[NumericGene]) – The genes from the second parent.

Returns:

The child genes resulting from crossover.

Return type:

List[NumericGene]

Raises:

ValueError – If the ‘between’ crossover method is not compatible with the gene type.

class lightweight_genetic_algorithm.crossover.CrossoverEitherOr[source]

Bases: Crossover

Implements an ‘either or’ crossover method where each child’s gene is randomly chosen to be either the corresponding gene from the first parent or from the second parent, with equal probability.

Note

  • The genes must have a ‘crossover_methods’ attribute that includes ‘either or’.

crossover(parent1_genes, parent2_genes)[source]

Perform ‘either or’ crossover between two parents.

Parameters:
  • parent1_genes (List[Gene]) – The genes from the first parent.

  • parent2_genes (List[Gene]) – The genes from the second parent.

Returns:

The child genes resulting from crossover. Each gene is chosen randomly from either parent.

Return type:

List[Gene]

Raises:

ValueError – If the ‘either or’ crossover method is not compatible with the gene type.

Notes

  • The returned genes are copies of the parent genes. This prevents unintended side effects if genes are mutable.

class lightweight_genetic_algorithm.crossover.CrossoverMidpoint[source]

Bases: Crossover

Implements a ‘midpoint’ crossover method where each child’s gene is the average (midpoint) of the corresponding genes of the two parents.

Note

  • The genes must have a ‘crossover_methods’ attribute that includes ‘midpoint’.

  • The genes must have ‘value’, ‘low’, and ‘high’ attributes.

crossover(parent1_genes, parent2_genes)[source]

Perform ‘midpoint’ crossover between two parents.

Parameters:
  • parent1_genes (List[NumericGene]) – The genes from the first parent.

  • parent2_genes (List[NumericGene]) – The genes from the second parent.

Returns:

The child genes resulting from crossover.

Return type:

List[NumericGene]

Raises:

ValueError – If the ‘midpoint’ crossover method is not compatible with the gene type.

lightweight_genetic_algorithm.mutation module

class lightweight_genetic_algorithm.mutation.Mutation(mutation_modes, mutation_probability, param_ranges)[source]

Bases: object

A class used to represent mutations in a genetic algorithm.

The Mutation class provides methods to mutate genes or individuals based on specified mutation modes and probabilities.

mutation_modes

List of mutation modes for each gene.

Type:

list of str

mutation_probability

Probability of mutating each gene.

Type:

float

param_ranges

List of parameter ranges for each gene.

Type:

list of tuple

is_categorical

Indicates if the genes are categorical.

Type:

bool

additive(gene, param_range)[source]

Applies an additive mutation to a gene.

The gene’s value is adjusted by adding a random value drawn from a normal distribution.

Parameters:
  • gene (Gene) – The gene to mutate.

  • param_range (tuple) – The (min, max) range of the gene’s parameter.

Returns:

The mutated gene.

Return type:

Gene

categorical(gene)[source]

Mutates a categorical gene by randomly reinitializing its value.

Parameters:

gene (Gene) – The categorical gene to mutate.

Returns:

The mutated gene.

Return type:

Gene

multiplicative(gene, param_range=None)[source]

Applies a multiplicative mutation to a gene.

The gene’s value is adjusted by multiplying it by a random factor drawn from a normal distribution centered at 1.

Parameters:
  • gene (Gene) – The gene to mutate.

  • param_range (tuple, optional) – Not used in this method.

Returns:

The mutated gene.

Return type:

Gene

mutate_genes(genes, force_mutate=False)[source]

Mutates a list of genes based on the mutation probability and modes.

Parameters:
  • genes (list of Gene) – A list of Gene objects to mutate.

  • force_mutate (bool, optional) – If True, ensures at least one gene is mutated.

Returns:

The mutated list of Gene objects.

Return type:

list of Gene

Raises:

ValueError – If a mutation mode is not compatible with a gene type.

mutate_individual(individual, force_mutate=False)[source]

Mutates an individual by mutating its genes.

Parameters:
  • individual (Individual) – The Individual object to mutate.

  • force_mutate (bool, optional) – If True, ensures at least one gene is mutated.

Returns:

A new Individual object with mutated genes.

Return type:

Individual

Raises:

TypeError – If the input is not an instance of Individual.

random(gene, param_range)[source]

Applies either an additive or multiplicative mutation to a gene at random.

Parameters:
  • gene (Gene) – The gene to mutate.

  • param_range (tuple) – The (min, max) range of the gene’s parameter.

Returns:

The mutated gene.

Return type:

Gene

lightweight_genetic_algorithm.population module

class lightweight_genetic_algorithm.population.CategoricalGene(categories, value=None)[source]

Bases: Gene

A categorical gene that can take any value from a set of categories.

Parameters:
  • categories (list) – The allowed categories for the gene.

  • value (object, optional) – The value of the gene. Must be one of the allowed categories. If not provided, the gene will be initialized with a random value.

categories

The allowed categories for the gene.

Type:

list

value

The current value of the gene.

Type:

object

random_initialization()[source]

Selects and returns a random value from the categories.

set_value(value)[source]

Sets the value of the gene to the specified value.

copy()[source]

Creates and returns a copy of the gene.

Raises:

ValueError – If the provided value is not in the allowed categories.

copy()[source]

Creates and returns a copy of the gene.

Returns:

A new instance of CategoricalGene with the same categories and value.

Return type:

CategoricalGene

crossover_methods = ['either or']
mutation_methods = ['categorical']
random_initialization()[source]

Selects and returns a random value from the categories.

Returns:

A random value from the allowed categories.

Return type:

object

set_value(value)[source]

Sets the value of the gene to the specified value.

Parameters:

value (object) – The new value for the gene.

Raises:

ValueError – If the provided value is not in the allowed categories.

class lightweight_genetic_algorithm.population.Gene[source]

Bases: ABC

Abstract base class for a gene.

Each subclass defines a gene in a specific genotype space.

mutation_methods

The mutation methods that can be applied to the gene.

Type:

list of str

random_initialization()[source]

Provides a random value appropriate for the gene.

set_value()[source]

Sets the value of the gene.

mutation_methods = []
abstract random_initialization()[source]

Provides a random value appropriate for the gene.

Returns:

A random value suitable for initializing the gene.

Return type:

value

abstract set_value()[source]

Sets the value of the gene.

Note

Implementation should define how the value is set.

class lightweight_genetic_algorithm.population.Individual(genes, fitness_function, fitness_function_args, fitness=None)[source]

Bases: object

Represents an individual in the population, defined by its genes.

Parameters:
  • genes (list of Gene) – The genes that define the individual.

  • fitness_function (callable) – The fitness function used to calculate the fitness of the individual. The function should take a list of gene values as its first argument and return a scalar value.

  • fitness_function_args (tuple) – Additional arguments for the fitness function.

  • fitness (float, optional) – The fitness of the individual. If not provided, the fitness function will be evaluated. This allows avoiding redundant evaluations of the fitness function.

genes

An array containing the genes of the individual.

Type:

numpy.ndarray

genes_values

An array containing the values of the genes.

Type:

numpy.ndarray

fitness_function

The fitness function used to calculate the fitness of the individual.

Type:

callable

fitness_function_args

Additional arguments for the fitness function.

Type:

tuple

fitness

The fitness of the individual.

Type:

float

get_genes()[source]

Returns a copy of the genes.

get_gene_values()[source]

Returns a copy of the gene values.

get_fitness_function()[source]

Returns the fitness function used by the individual.

copy()[source]

Creates and returns a copy of the individual.

Raises:

ValueError – If the fitness function evaluation fails, indicating incompatibility with the individual’s genes.

copy()[source]

Creates and returns a copy of the individual.

Returns:

A new Individual instance with the same genes and fitness.

Return type:

Individual

get_fitness_function()[source]

Returns the fitness function used by the individual.

Returns:

The fitness function.

Return type:

callable

get_gene_values()[source]

Returns a copy of the gene values.

Returns:

An array containing the values of the individual’s genes.

Return type:

numpy.ndarray

get_genes()[source]

Returns a copy of the genes.

Returns:

An array containing copies of the individual’s genes.

Return type:

numpy.ndarray

class lightweight_genetic_algorithm.population.NumericGene(gene_range, value=None)[source]

Bases: Gene

A numeric gene represented by a real number within a range.

Parameters:
  • gene_range (tuple of float) – The range (low, high) of the gene values.

  • value (float, optional) – The value of the gene. If not provided, the gene will be initialized with a random value.

low

The lower bound of the gene values.

Type:

float

high

The upper bound of the gene values.

Type:

float

value

The current value of the gene.

Type:

float

get_gene_range()[source]

Returns the gene range as a tuple (low, high).

random_initialization()[source]

Generates and returns a random value within the gene range.

set_value(value)[source]

Sets the value of the gene to the specified value.

copy()[source]

Creates and returns a copy of the gene.

copy()[source]

Creates and returns a copy of the gene.

Returns:

A new instance of NumericGene with the same range and value.

Return type:

NumericGene

crossover_methods = ['between', 'midpoint', 'either or']
get_gene_range()[source]

Returns the gene range.

Returns:

A tuple (low, high) representing the gene range.

Return type:

tuple of float

mutation_methods = ['additive', 'multiplicative', 'random']
random_initialization()[source]

Generates and returns a random value within the gene range.

Returns:

A random value within the gene range.

Return type:

float

set_value(value)[source]

Sets the value of the gene to the specified value.

Parameters:

value (float) – The new value for the gene.

lightweight_genetic_algorithm.selection module

class lightweight_genetic_algorithm.selection.DiversityEnhancedSurvivorSelection(measure, r0=None, D0=None)[source]

Bases: SurvivorSelection

Diversity-enhanced survivor selection strategy.

This class implements a survivor selection method that considers both the fitness and the diversity of individuals. It aims to maintain diversity in the population by penalizing individuals that are too similar to already selected survivors.

Parameters:
  • measure (callable or {'euclidean', 'hamming', 'dynamic'}) – A function to measure the distance or dissimilarity between two individuals. If a string is provided, it must be one of the predefined measures: - ‘euclidean’: Sum of squared differences (Euclidean distance squared). - ‘hamming’: Hamming distance normalized by the length of the vectors. - ‘dynamic’: Dynamic distance considering relative differences.

  • r0 (float, optional) – The characteristic distance beyond which there is no diversity penalty. Default is 1.0.

  • D0 (float, optional) – The maximum diversity penalty for identical individuals. Default is 1.0.

r0

Characteristic distance for diversity calculation.

Type:

float

D0

Maximum diversity penalty.

Type:

float

measure

Function to compute the distance between two individuals.

Type:

callable

compute_diversity(individual, survivor)[source]

Compute the diversity penalty between an individual and a selected survivor.

The penalty decreases exponentially with the squared distance between the individual and the survivor.

Parameters:
  • individual (object) – An individual from the population. Must have a method get_gene_values() that returns a numpy array of gene values.

  • survivor (object) – A survivor individual already selected. Must have a method get_gene_values() that returns a numpy array of gene values.

Returns:

The diversity penalty for the individual.

Return type:

float

select_survivors(population, surviving_population_size)[source]

Select survivors from the population based on fitness and diversity.

The method iteratively selects the best individual (based on adjusted fitness), adds it to the list of survivors, and updates the fitness of the remaining individuals by subtracting the diversity penalty with respect to the newly added survivor.

Parameters:
  • population (list) – A list of individuals in the current population. Each individual must have a fitness attribute and a get_gene_values() method.

  • surviving_population_size (int) – The number of individuals to select as survivors.

Returns:

A list of selected individuals of length surviving_population_size.

Return type:

list

Notes

The method modifies the input population list by removing selected survivors.

class lightweight_genetic_algorithm.selection.FitnessProportionalSurvivorSelection[source]

Bases: SurvivorSelection

Fitness-proportional survivor selection strategy.

This class implements a survivor selection method where individuals are selected based solely on their fitness values. Individuals with higher fitness have a higher chance of being selected.

select_survivors(population, surviving_population_size)[source]

Select survivors from the population based on fitness.

Parameters:
  • population (list) – A list of individuals in the current population. Each individual must have a fitness attribute.

  • surviving_population_size (int) – The number of individuals to select as survivors.

Returns:

A list of selected individuals of length surviving_population_size.

Return type:

list

class lightweight_genetic_algorithm.selection.SurvivorSelection[source]

Bases: object

Base class for survivor selection methods in evolutionary algorithms.

This abstract class defines the interface for survivor selection strategies. Subclasses should implement the select_survivors method to specify how survivors are selected from a population.

select_survivors(population, surviving_population_size)[source]

Select survivors from the population.

Parameters:
  • population (list) – A list of individuals in the current population.

  • surviving_population_size (int) – The number of individuals to select as survivors.

Returns:

A list of selected individuals of length surviving_population_size.

Return type:

list

Raises:

NotImplementedError – If the method is not implemented in the subclass.

Module contents

The lightweight_genetic_algorithm package An intuitive, flexible and efficient implementation of a genetic algorithm in Python