stk.ShiftUp

class stk.ShiftUp(filter=<function ShiftUp.<lambda>>)[source]

Bases: FitnessNormalizer[T]

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, for example, [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 elements 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

[1, -5, 5]
[3, -10, 2]
[2, 20, 1]

After normalization the fitness values will be.

[1, 6, 5]
[3, 1, 2]
[2, 31, 1]

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

Examples

Ensuring Positive Fitness Values

Here you final fitness value is calculated by taking a Sum of the different components of the fitness value. To ensure that the final sum is positive, each component must also be positive.

import stk
import numpy as np

building_block = stk.BuildingBlock('BrCCBr', stk.BromoFactory())
record1 = stk.MoleculeRecord(
    topology_graph=stk.polymer.Linear(
        building_blocks=[building_block],
        repeating_unit='A',
        num_repeating_units=2,
    ),
)
record2 = stk.MoleculeRecord(
    topology_graph=stk.polymer.Linear(
        building_blocks=[building_block],
        repeating_unit='A',
        num_repeating_units=2,
    ),
)
fitness_values = {
    record1: (1, -2, 3),
    record2: (4, 5, -6),
}

# Create the normalizer.
shifter = stk.ShiftUp()

normalized_fitness_values = shifter.normalize(fitness_values)
assert np.all(np.equal(
    normalized_fitness_values[record1],
    (1, 1, 10),
))
assert np.all(np.equal(
    normalized_fitness_values[record2],
    (4, 8, 1),
))

Selectively Normalizing Fitness Values

Sometimes, you only want to normalize some members of a population, for example if some do not have an assigned fitness value, because the fitness calculation failed for whatever reason. You can use the filter parameter to exclude records from the normalization

import stk
import numpy as np

building_block = stk.BuildingBlock('BrCCBr', stk.BromoFactory())
record1 = stk.MoleculeRecord(
    topology_graph=stk.polymer.Linear(
        building_blocks=[building_block],
        repeating_unit='A',
        num_repeating_units=2,
    ),
)
record2 = stk.MoleculeRecord(
    topology_graph=stk.polymer.Linear(
        building_blocks=[building_block],
        repeating_unit='A',
        num_repeating_units=2,
    ),
)
fitness_values = {
    record1: (1, -2, 3),
    record2: None,
}
normalizer = stk.ShiftUp(
    # Only normalize values which are not None.
    filter=lambda fitness_values, record:
        fitness_values[record] is not None,
)
normalized_fitness_values = normalizer.normalize(fitness_values)
assert np.all(np.equal(
    normalized_fitness_values[record1],
    (1, 1, 3),
))
assert normalized_fitness_values[record2] is None
Parameters:

filter (Callable[[dict[T, Any], T], bool]) – A function which returns True or False. Only molecules which return True will have fitness values normalized. By default, all molecules will have fitness values normalized. The instance passed to the fitness_values argument of normalize() is passed as the first argument, while the second argument will be passed every MoleculeRecord in it, one at a time.

Methods

normalize

Normalize some fitness values.

normalize(fitness_values)[source]

Normalize some fitness values.

Parameters:

fitness_values (dict[T, Any]) – The molecules which need to have their fitness values normalized.

Returns:

The new fitness value for each molecule.

Return type:

dict[T, Any]