Crossover¶
Crossover operators define how new individuals are generated from one or more existing individuals. They are configured using the Operators class and can be supplied to LLaMEA through the operators parameter.
Operators
An operator is defined as follows:
from dataclasses import dataclass, field
import uuid
@dataclass
class Operators:
prompt: str
name: str = "mutation"
weight: float = field(default=0.5, compare=False)
number_of_parents: int = 1
def __post_init__(self):
self.id = uuid.uuid4().hex
self.rewards = 0.0
Parameters
prompt(str)Instructions describing the operation to perform. The prompt is appended to the end of the
LLaMEA.task_promptwhen the operator is selected.name(str, default:"mutation")The name of the operator. Use this to identify or distinguish different mutation and crossover strategies.
weight(float, default:0.5)Determines the relative probability that the operator will be selected. Operators with larger weights are more likely to be selected than operators with smaller weights. The weight must be a non-negative real number.
number_of_parents(int, default:1)Specifies how many individuals from the parent population are used to construct the prompt for generating the next individual. Valid values are
1 <= number_of_parents <= parent_populationid(str)A unique identifier automatically generated during initialization using
uuid.uuid4().hex. It is used by theWeightUpdaterto associate rewards and weights with individual operators.rewards(float)Stores the reward accumulated by the operator. Rewards are provided by LLaMEA based on the performance of offspring relative to their parent(s).
When providing operators with number_of_parents > 1, one an also use LLaMEA’s parameter:
parent_selection: str
For operators with number_of_parents > 1, use the parent_selection parameter to specify how parents are selected.
- Supported strategies are:
“random”(default) – randomly selects parents from the parent population.
“tournament” – selects parents using tournament-based selection.
“roulette” – selects parents according to their relative fitness.
For example:
operator = Operators(
prompt="Combine useful properties from the selected parents.",
name="crossover"",
number_of_parents=2,
)
Using operators with LLaMEA
- Operators are provided to LLaMEA as a list:
operators = [ mutation_operator, crossover_operator, ] llamea = LLaMEA( ..., operators=operators, parent_selection='roulette', ... )
WeightUpdater¶
WeightUpdater is an abstract base class responsible for dynamically updating operator weights based on their observed performance.
Implementations must provide the following two methods:
class WeightUpdater(ABC):
def __init__(self, operator_ids: list[str]) -> object:
...
def update(self, id: str, reward: float) -> float:
...
__init__
The initializer receives a list of operator IDs:
operator_ids: list[str]
These IDs are used to maintain state for each operator.
update
- The
updatemethod receives: id– the ID of the operator whose weight should be updated.reward– the reward assigned to the operator by LLaMEA.
The reward reflects the performance of the generated offspring relative to its parent or parents. The method returns the operator’s updated weight.
DefaultWeightUpdater¶
DefaultWeightUpdater provides the default weight-update behaviour.
It does not adapt operator weights based on rewards. Whenever an operator is updated, its weight is set to 1.0.
This results in equal relative selection weights for all operators using this updater.
DiscountedUCBState¶
DiscountedUCBState is a WeightUpdater implementation based on a discounted Upper Confidence Bound (UCB) strategy, similar to the approach used in Monte Carlo Tree Search.
Unlike DefaultWeightUpdater, it adapts operator weights according to their observed rewards while accounting for both exploitation and exploration.
Configuration
gamma(float, default:0.95)Reward discount factor. A higher value gives more importance to historical rewards, resulting in slower discounting of past observations.
c(float, default:1.0)Exploration coefficient controlling the contribution of the UCB exploration bonus. Higher values encourage greater exploration of less frequently selected operators.
For example:
weight_updater = DiscountedUCBState(
operator_ids=[operator.id for operator in operators],
gamma=0.95,
c=1.0,
)
Configuring weight updaters
Any instance of a class derived from
WeightUpdatercan be passed to LLaMEA using theoperator_weight_updaterparameter:
llamea = LLaMEA(
...,
operators=operators,
operator_weight_updater=weight_updater,
)
This allows for custom implementation of operator weight update strategy.