Fitness Normalizers

  1. NullFitnessNormalizer

  2. Power

  3. Multiply

  4. Sum

  5. DivideByMean

  6. ShiftUp

  7. If

  8. TryCatch

  9. Sequence

  10. Random

  11. RaisingCalculator

Fitness normalizers are classes which are responsible for normalizing the fitness values in an EAPopulation. They analyze the fitness values across the entire population and calculate new ones.

To see how FitnessNormalizer can be used, look at the documention of the classes which inherit it, for example Power, Sum DivideByMean. In addition, multiple FitnessNormalizer can be chained using Sequence().

Making New Fitness Normalizers

A new class inheriting FitnessNormalizer must be made. This is an abstract base class so its virtual methods need to be implemented.

class DivideByMean(filter=<function DivideByMean.<lambda>>)

Bases: stk.calculators.ea.fitness_normalizers._FilteringNormalizer, stk.calculators.ea.fitness_normalizers.FitnessNormalizer

Divides fitness values by the population mean.

While this function can be used if the fitness value of each Molecule in the EAPopulation is a single number, it is most useful when the fitness values is a list of numbers. In this case, it is necessary to somehow combine the numbers so that a single fitness value is produced. For example, take a fitness value which is the vector holding the properties [energy, diameter, num_atoms]. For a given molecule these numbers may be something like [200,000, 12, 140]. If we were to sum these numbers, the energy term would dominate the final fitness value. In order to combine these numbers we can divide them by the population averages. For example, if the average energy of molecules in the population is 300,000 the average diameter is 10 and the average number of atoms is 70 then the fitness vector would be scaled to [0.5, 1.2, 2]. These numbers are now of a similar magnitude and can be summed to give a reasonable value. After division , each value represents how much better than the population average each property value is. In essence we have removed the units from each parameter.

Examples

Scale fitness values

import stk

mean_scaler = stk.DivideByMean()

# Normalize the fitness values.
# Assume the fitness values are
# {mol1: 1, mol2: 2, mol3: 3}
normalized = mean_scaler.normalize(pop)

# normalized is
# {mol1: 0.5, mol2: 1, mol3: 1.5}

Scale fitness vectors

# Create the normalizer.
# mean_scaler = DivideByMean()

# Normalize the fitness values.
# Assume the fitness values are
# {mol1: [1, 10, 100], mol2: [2, 20, 100], mol3: [3, 30, 100]}.
normalized = mean_scaler.normalize(pop)

# normalized is
# {
#     mol1: [0.5, 0.5, 0.5],
#     mol2: [1, 1, 1],
#     mol3: [1.5, 1.5, 1.5]
# }.

Methods

normalize(self, population)

Normalize the fitness values in population.

__init__(self, filter=<function DivideByMean.<lambda> at 0x7fcf9d155d40>)

Initialize a DivideByMean instance.

Parameters

filter (callable, optional) – Takes a two parameters, first is a EAPopulation and the second is a Molecule, and returns True or False. Only molecules which return True will have fitness values normalized. By default, all molecules will have fitness values normalized. The EAPopulation on which normalize() is called is passed as the first argument while the second argument will be passed every Molecule in it.

normalize(self, population)

Normalize the fitness values in population.

Parameters

population (EAPopulation) – The molecules which need to have their fitness values normalized.

Returns

Maps every molecule in population to its normalized fitness value.

Return type

dict

class FitnessNormalizer

Bases: stk.calculators.base_calculators.Calculator

Abstract base class for fitness normalizers.

A fitness normalizer takes an EAPopulation and returns a new set of normalized fitness values for all molecules in it. The primary benefit of a normalizer vs a FitnessCalculator is that a FitnessNormalizer has access to all members in the population when it is calculating the new fitness value, whereas a FitnessCalculator does not.

Methods

normalize(self, population)

Normalize the fitness values in population.

__init__(self, /, *args, **kwargs)

Initialize self. See help(type(self)) for accurate signature.

normalize(self, population)

Normalize the fitness values in population.

Parameters

population (EAPopulation) – The molecules which need to have their fitness values normalized.

Returns

Maps every molecule in population to its normalized fitness value.

Return type

dict

class Multiply(coefficient, filter=<function Multiply.<lambda>>)

Bases: stk.calculators.ea.fitness_normalizers._FilteringNormalizer, stk.calculators.ea.fitness_normalizers.FitnessNormalizer

Multiplies the fitness values by some coefficient.

Examples

Multiplying a fitness value by a coefficient.

import stk

# Create the normalizer.
multiply = stk.Multiply(2)

# Normalize the fitness values. Assume the fitness values are
# {mol1: 1, mol2: 2, mol3: 3}.
normalized = multiply.normalize(pop)

# normalized is
# {mol1: 2, mol2: 4, mol3: 6}.

Multiplying a vector of fitness values by some coefficient

multiply = stk.Multiply(2)

# Normalize the fitness values. Assume the fitness values are
# {mol1: [1, 2, 3], mol2: [4, 5, 6], mol3: [7, 8, 9]}.
normalized = multiply.normalize(pop)

# normalized is
# {mol1: [2, 4, 6], mol2: [8, 10, 12], mol3: [14, 16, 18]}.

Multiplying a vector of fitness values by different coefficients

multiple = stk.Multiply([1, 2, 3])

# Normalize the fitness values. Assume the fitness values are
# {mol1: [1, 2, 3], mol2: [4, 5, 6], mol3: [7, 8, 9]}.
normalized = multiply.normalize(pop)

# normalized is
# {mol1: [1, 4, 9], mol2: [4, 10, 18], mol3: [7, 16, 27]}.

Methods

normalize(self, population)

Normalize the fitness values in population.

__init__(self, coefficient, filter=<function Multiply.<lambda> at 0x7fcf9d1559e0>)

Initialize a Multiply instance.

Parameters
  • coefficient (float or list of float) – The coefficients each fitness value by. Can be a single number or multiple numbers.

  • filter (callable, optional) – Takes a two parameters, first is a EAPopulation and the second is a Molecule, and returns True or False. Only molecules which return True will have fitness values normalized. By default, all molecules will have fitness values normalized. The EAPopulation on which normalize() is called is passed as the first argument while the second argument will be passed every Molecule in it.

normalize(self, population)

Normalize the fitness values in population.

Parameters

population (EAPopulation) – The molecules which need to have their fitness values normalized.

Returns

Maps every molecule in population to its normalized fitness value.

Return type

dict

class NullFitnessNormalizer

Bases: stk.calculators.ea.fitness_normalizers.FitnessNormalizer

Does nothing.

Methods

normalize(self, population)

Normalize the fitness values in population.

__init__(self, /, *args, **kwargs)

Initialize self. See help(type(self)) for accurate signature.

normalize(self, population)

Normalize the fitness values in population.

Parameters

population (EAPopulation) – The molecules which need to have their fitness values normalized.

Returns

Maps every molecule in population to its normalized fitness value.

Return type

dict

class Power(power, filter=<function Power.<lambda>>)

Bases: stk.calculators.ea.fitness_normalizers._FilteringNormalizer, stk.calculators.ea.fitness_normalizers.FitnessNormalizer

Raises fitness values to some power.

This works for cases where the fitness value is single float and where it is list of float.

Examples

Raising a fitness value by some power

import stk

pop = stk.Population(...)
# Assume this returns {mol1: 1, mol2: 2, mol3: 3}.
pop.get_fitness_values()

# Create the normalizer.
power = stk.Power(2)

# Normalize the fitness values.
normalized = power.normalize(pop)

# normalized is {mol1: 1, mol2: 4, mol3: 9}.

Raising vector valued fitness values by some power

# Create the normalizer.
power = stk.Power(2)

# Normalize the fitness values. Assume the fitness values are
# {mol1: [1, 2, 3], mol2: [4, 5, 6], mol3: [7, 8, 9]}.
normalized = power.normalize(pop)

# normalized is
# {mol1: [1, 4, 9], mol2: [16, 25, 36], mol3: [49, 64, 81]}.

Raising vector valued fitness values by different powers

# Create the normalizer.
power = stk.Power([1, 2, 3])

# Normalize the fitness values. Assume the fitness values are
# {mol1: [1, 2, 3], mol2: [4, 5, 6], mol3: [7, 8, 9]}.

# Normalize the fitness values.
normalized = power.normalize(pop)

# normalized is
# {mol1: [1, 4, 27], mol2: [4, 25, 216], mol3: [7, 64, 729]}.

Methods

normalize(self, population)

Normalize the fitness values in population.

__init__(self, power, filter=<function Power.<lambda> at 0x7fcf9d155830>)

Initialize a Power instance.

Parameters
  • power (float or list of float) – The power to raise each fitness value to. Can be a single number or multiple numbers.

  • filter (callable, optional) – Takes a two parameters, first is a EAPopulation and the second is a Molecule, and returns True or False. Only molecules which return True will have fitness values normalized. By default, all molecules will have fitness values normalized. The EAPopulation on which normalize() is called is passed as the first argument while the second argument will be passed every Molecule in it.

normalize(self, population)

Normalize the fitness values in population.

Parameters

population (EAPopulation) – The molecules which need to have their fitness values normalized.

Returns

Maps every molecule in population to its normalized fitness value.

Return type

dict

class ReplaceFitness(replacement_fn, filter=<function ReplaceFitness.<lambda>>)

Bases: stk.calculators.ea.fitness_normalizers.FitnessNormalizer

Replaces fitness values of a certain value with a new value.

Examples

Replace all fitness values which are None with the half the minimum fitness value in the population

import stk

replacer = stk.ReplaceFitness(
    replacement_fn=lambda population:
        min(
            f for _, f in population.get_fitness_values()
            if f is not None
        ) / 2,
    filter=lambda population, mol:
        population.get_fitness_values()[mol] is None,
)

Methods

normalize(self, population)

Normalize the fitness values in population.

__init__(self, replacement_fn, filter=<function ReplaceFitness.<lambda> at 0x7fcf9d1570e0>)

Initialize a ReplaceFitness instance.

Parameters
  • replacement_fn (callable) – Takes a single parameter, the Population which needs to be normalized, before it is filtered, and returns an object which is used as the new fitness value for all molecules which pass the filter.

  • filter (callable, optional) – Takes a two parameters, first is a EAPopulation and the second is a Molecule, and returns True or False. Only molecules which return True will have fitness values replaced. By default, all molecules will have fitness values replaced. The EAPopulation on which normalize() is called is passed as the first argument while the second argument will be passed every Molecule in it.

normalize(self, population)

Normalize the fitness values in population.

Parameters

population (EAPopulation) – The molecules which need to have their fitness values normalized.

Returns

Maps every molecule in population to its normalized fitness value.

Return type

dict

class ShiftUp(filter=<function ShiftUp.<lambda>>)

Bases: stk.calculators.ea.fitness_normalizers._FilteringNormalizer, stk.calculators.ea.fitness_normalizers.FitnessNormalizer

Shifts negative fitness values to be positive.

Assume you have a vector-valued fitness value, where each number represents a different property of the molecule

{mol1: [1, -10, 1]}

One way to convert the vector-valued fitness value into a scalar fitness value is by summing the elements, and the result in this case would be -8. Clearly this doesn’t work, because the resulting fitness value is not a positive number. To fix this, the -10 should be shifted to a positive value.

ShiftUp finds the minimum value of each element in the vector-valued fitness value across the entire population, and for element where this minimum value is less than 0, shifts up the element value for every molecule in the population, so that the minimum value in the entire population is 1.

For example, take a population with the vector-valued fitness values

fitness_values = {
    mol1: [1, -5, 5],
    mol2: [3, -10, 2],
    mol3: [2, 20, 1],
}

After normalization the fitness values will be.

normalized  = {
    mol1: [1, 6, 5],
    mol2: [3, 1, 2],
    mol3: [2, 31, 1],
}

This ShiftUp also works when the fitness value is a single value.

Examples

# Create the normalizer.
shifter = ShiftUp()

# Normalize the fitness values. Assume the fitness values are
# {mol1: [1, -2, 3], mol2: [4, 5, -6], mol3: [7, 8, 9]}.
normalized = shifter.normalize(pop)

# normalized is
# {mol1: [1, 1, 10], mol2: [4, 8, 1], mol3: [7, 11, 16]}.

Methods

normalize(self, population)

Normalize the fitness values in population.

__init__(self, filter=<function ShiftUp.<lambda> at 0x7fcf9d155ef0>)

Initialize a ShiftUp instance.

Parameters

filter (callable, optional) – Takes a two parameters, first is a EAPopulation and the second is a Molecule, and returns True or False. Only molecules which return True will have fitness values normalized. By default, all molecules will have fitness values normalized. The EAPopulation on which normalize() is called is passed as the first argument while the second argument will be passed every Molecule in it.

normalize(self, population)

Normalize the fitness values in population.

Parameters

population (EAPopulation) – The molecules which need to have their fitness values normalized.

Returns

Maps every molecule in population to its normalized fitness value.

Return type

dict

class Sum(filter=<function Sum.<lambda>>)

Bases: stk.calculators.ea.fitness_normalizers._FilteringNormalizer, stk.calculators.ea.fitness_normalizers.FitnessNormalizer

Sums the values in a list.

Examples

# Create the normalizer.
sum_normalizer = stk.Sum()

# Normalize the fitness values. Assume the fitness values are
# {mol1: [1, 2, 3], mol2: [4, 5, 6], mol3: [7, 8, 9]}.
normalized = sum_normalizer.normalize(pop)

# normalized is
# {mol1: 6, mol2: 15, mol3: 24}

Methods

normalize(self, population)

Normalize the fitness values in population.

__init__(self, filter=<function Sum.<lambda> at 0x7fcf9d155b90>)

Initialize a Sum instance.

Parameters

filter (callable, optional) – Takes a two parameters, first is a EAPopulation and the second is a Molecule, and returns True or False. Only molecules which return True will have fitness values normalized. By default, all molecules will have fitness values normalized. The EAPopulation on which normalize() is called is passed as the first argument while the second argument will be passed every Molecule in it.

normalize(self, population)

Normalize the fitness values in population.

Parameters

population (EAPopulation) – The molecules which need to have their fitness values normalized.

Returns

Maps every molecule in population to its normalized fitness value.

Return type

dict