Source code for stk._internal.ea.fitness_normalizers.sum

import typing
from collections.abc import Callable
from typing import Any

from .fitness_normalizer import FitnessNormalizer

T = typing.TypeVar("T")


[docs] class Sum(FitnessNormalizer[T]): """ Combines fitness value components into a single fitness value. Examples: *Combining Fitness Value Components Into a Single Value* Sometimes, your :class:`.FitnessCalculator` will return a fitness value which is a :class:`tuple` of multiple numbers. Each number represents a different property of the molecule, which contributes to the final fitness value. This fitness normalizer combines these fitness value components into a single number, by taking their sum. .. testcode:: combining-fitness-value-components import stk building_block = stk.BuildingBlock('BrCCBr', stk.BromoFactory()) record = stk.MoleculeRecord( topology_graph=stk.polymer.Linear( building_blocks=[building_block], repeating_unit='A', num_repeating_units=2, ), ) fitness_values = { record: (1, -2, 3), } sum_normalizer = stk.Sum() normalized_fitness_values = sum_normalizer.normalize( fitness_values=fitness_values, ) assert normalized_fitness_values[record] == 2 *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 .. testcode:: selectively-normalizing-fitness-values import stk 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.Sum( # 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 normalized_fitness_values[record1] == 2 assert normalized_fitness_values[record2] is None """ def __init__( self, filter: Callable[[dict[T, Any], T], bool] = lambda fitness_values, record: True, ) -> None: """ Parameters: filter: A function wihch 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 :meth:`.normalize` is passed as the first argument, while the second argument will be passed every :class:`.MoleculeRecord` in it, one at a time. """ self._filter = filter
[docs] def normalize(self, fitness_values: dict[T, Any]) -> dict[T, Any]: return { record: ( sum(fitness_value) if self._filter(fitness_values, record) else fitness_value ) for record, fitness_value in fitness_values.items() }