evolve¶
Genetic algorithm. Maintains a population, combines solutions via crossover, occasionally mutates. Slower than single-solution methods but explores more diversity. Good for multi-objective problems.
Signature¶
def evolve[T](
objective_fn: Callable[[T], float],
population: Sequence[T],
crossover: Callable[[T, T], T],
mutate: Callable[[T], T],
*,
generations: int = 100,
elite_size: int = 2,
mutation_rate: float = 0.1,
adaptive_mutation: bool = False,
on_progress: Callable[[Progress], bool | None] | None = None,
progress_interval: int = 0,
) -> Result[T]
Parameters¶
| Parameter | Description |
|---|---|
objective_fn |
Function to minimize |
population |
Initial population of solutions |
crossover |
Combine two parents into child |
mutate |
Randomly modify a solution |
generations |
Number of generations |
elite_size |
Keep best N across generations |
mutation_rate |
Probability of mutation |
adaptive_mutation |
Increase rate when stuck |
Example¶
from solvor import evolve
import random
def fitness(x):
return sum(xi**2 for xi in x)
def crossover(a, b):
# Uniform crossover
return [ai if random.random() < 0.5 else bi for ai, bi in zip(a, b)]
def mutate(x):
x = list(x)
i = random.randint(0, len(x)-1)
x[i] += random.gauss(0, 0.5)
return x
population = [[random.uniform(-10, 10) for _ in range(5)] for _ in range(50)]
result = evolve(fitness, population, crossover, mutate, generations=100)
print(result.solution) # Close to [0, 0, 0, 0, 0]
How It Works¶
- Evaluate fitness of all individuals
- Select parents (tournament selection)
- Crossover parents to create children
- Mutate children with some probability
- Keep elite individuals unchanged
- Replace population and repeat
Tips¶
- Crossover is critical. Bad crossover = expensive random search.
- Elite preservation. Keep the best solutions across generations.
- Adaptive mutation. Enable to escape plateaus.
See Also¶
- differential_evolution - For continuous spaces
- particle_swarm - Another population method