# Shift Up¶

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

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(
smiles='BrCCBr',
functional_groups=[stk.BromoFactory()],
)

population = (
stk.MoleculeRecord(
topology_graph=stk.polymer.Linear(
building_blocks=(building_block, ),
repeating_unit='A',
num_repeating_units=2,
),
).with_fitness_value(
fitness_value=(1, -2, 3),
normalized=False,
),
stk.MoleculeRecord(
topology_graph=stk.polymer.Linear(
building_blocks=(building_block, ),
repeating_unit='A',
num_repeating_units=2,
),
).with_fitness_value(
fitness_value=(4, 5, -6),
normalized=False,
),
)

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

normalized_population = tuple(shifter.normalize(population))
normalized_record1, normalized_record2 = normalized_population
assert np.all(np.equal(
normalized_record1.get_fitness_value(),
(1, 1, 10),
))
assert np.all(np.equal(
normalized_record2.get_fitness_value(),
(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(
smiles='BrCCBr',
functional_groups=[stk.BromoFactory()],
)

population = (
stk.MoleculeRecord(
topology_graph=stk.polymer.Linear(
building_blocks=(building_block, ),
repeating_unit='A',
num_repeating_units=2,
),
).with_fitness_value(
fitness_value=(1, -2, 3),
normalized=False,
),
# This will have a fitness value of None.
stk.MoleculeRecord(
topology_graph=stk.polymer.Linear(
building_blocks=(building_block, ),
repeating_unit='A',
num_repeating_units=2,
),
),
)

normalizer = stk.ShiftUp(
# Only normalize values which are not None.
filter=lambda population, record:
record.get_fitness_value() is not None,
)
normalized_population = tuple(normalizer.normalize(population))
normalized_record1, normalized_record2 = normalized_population
assert np.all(np.equal(
normalized_record1.get_fitness_value(),
(1, 1, 3),
))
assert normalized_record2.get_fitness_value() is None
```

Methods

 `normalize`(population) Normalize the fitness values in population.
`__init__`(filter=<function ShiftUp.<lambda>>)[source]

Initialize a `ShiftUp` instance.

Parameters

filter (`callable`, optional) – Takes two parameters, first is a `tuple` of `MoleculeRecord` instances, and the second is a `MoleculeRecord`. The `callable` 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 population argument of `normalize()` is passed as the first argument, while the second argument will be passed every `MoleculeRecord` in it, one at a time.

`normalize`(population)[source]

Normalize the fitness values in population.

Parameters

population (`tuple` of `MoleculeRecord`) – The molecules which need to have their fitness values normalized.

Yields

`MoleculeRecord` – A record with a normalized fitness value.