Fitness Normalizers¶
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 theEAPopulation
is a single number, it is most useful when the fitness values is alist
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 is300,000
the average diameter is10
and the average number of atoms is70
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 aEAPopulation
and the second is aMolecule
, and returnsTrue
orFalse
. Only molecules which returnTrue
will have fitness values normalized. By default, all molecules will have fitness values normalized. TheEAPopulation
on whichnormalize()
is called is passed as the first argument while the second argument will be passed everyMolecule
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 aFitnessCalculator
is that aFitnessNormalizer
has access to all members in the population when it is calculating the new fitness value, whereas aFitnessCalculator
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
orlist
offloat
) – The coefficients eachfitness
value by. Can be a single number or multiple numbers.filter (
callable
, optional) – Takes a two parameters, first is aEAPopulation
and the second is aMolecule
, and returnsTrue
orFalse
. Only molecules which returnTrue
will have fitness values normalized. By default, all molecules will have fitness values normalized. TheEAPopulation
on whichnormalize()
is called is passed as the first argument while the second argument will be passed everyMolecule
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 islist
offloat
.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
orlist
offloat
) – The power to raise eachfitness
value to. Can be a single number or multiple numbers.filter (
callable
, optional) – Takes a two parameters, first is aEAPopulation
and the second is aMolecule
, and returnsTrue
orFalse
. Only molecules which returnTrue
will have fitness values normalized. By default, all molecules will have fitness values normalized. TheEAPopulation
on whichnormalize()
is called is passed as the first argument while the second argument will be passed everyMolecule
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 populationimport 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, thePopulation
which needs to be normalized, before it is filtered, and returns anobject
which is used as the new fitness value for all molecules which pass the filter.filter (
callable
, optional) – Takes a two parameters, first is aEAPopulation
and the second is aMolecule
, and returnsTrue
orFalse
. Only molecules which returnTrue
will have fitness values replaced. By default, all molecules will have fitness values replaced. TheEAPopulation
on whichnormalize()
is called is passed as the first argument while the second argument will be passed everyMolecule
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 than0
, shifts up the element value for every molecule in the population, so that the minimum value in the entire population is1
.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 aEAPopulation
and the second is aMolecule
, and returnsTrue
orFalse
. Only molecules which returnTrue
will have fitness values normalized. By default, all molecules will have fitness values normalized. TheEAPopulation
on whichnormalize()
is called is passed as the first argument while the second argument will be passed everyMolecule
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 aEAPopulation
and the second is aMolecule
, and returnsTrue
orFalse
. Only molecules which returnTrue
will have fitness values normalized. By default, all molecules will have fitness values normalized. TheEAPopulation
on whichnormalize()
is called is passed as the first argument while the second argument will be passed everyMolecule
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
-