seachange
seachange runs generational evolutionary algorithms and keeps every individual in a SQLite database. You write each step of a generation (evaluate, select, mutate, retire) as a plain function that takes a population and returns one. The engine runs those functions in order once per generation and saves the result. Because every generation is on disk, you can stop a run, query it afterwards, or restart it from any generation.
It started as the evolution engine of ARIEL, a robot evolution framework, and holds the parts that have nothing to do with robots: the engine, random generators and mutators for integer and float genomes, crossover operators, and a RevDE optimizer.
Installation
seachange needs Python 3.13 or later. It is not on PyPI yet, so install it from a local clone:
git clone https://github.com/Jacopo-DM/seachange seachange
uv add ./seachange
Example
One-max: evolve 20-bit strings until every bit is 1. Each generation adds one mutated child per parent from the better half, scores the new individuals, and retires the worst so twenty stay alive.
from typing import cast
from seachange import (
EA,
EAOperation,
Individual,
IntegerMutator,
IntegersGenerator,
Population,
)
SIZE, LENGTH = 20, 20
def random_individual() -> Individual:
individual = Individual()
individual.genotype = IntegersGenerator.integers(
low=0, high=1, size=LENGTH, endpoint=True
)
return individual
def evaluate(population: Population) -> Population:
for individual in population.unevaluated:
individual.fitness = sum(cast("list[int]", individual.genotype))
return population
def reproduce(population: Population) -> Population:
for parent in population.best(n=SIZE // 2):
child = Individual()
child.genotype = IntegerMutator.random_reset(
cast("list[int]", parent.genotype),
low=0,
high=1,
mutation_probability=1 / LENGTH,
)
population.append(child)
return population
def retire_worst(population: Population) -> Population:
for individual in population.sort()[SIZE:]:
individual.alive = False
return population
first = Population([random_individual() for _ in range(SIZE)])
ea = EA(
evaluate(first),
[EAOperation(reproduce), EAOperation(evaluate), EAOperation(retire_worst)],
num_steps=50,
)
ea.run()
print(ea.get_solution("best").genotype)
It prints a progress bar and then the best bit string, all ones after 50 generations. The run is saved in __data__/database.db under the current folder; pass db_file_path= to EA to put it elsewhere. The same example, documented, is in examples/a1_one_max.py.
To continue a saved run, pass its database to EA.restart and give the new run its own file:
from pathlib import Path
ea = EA.restart(
"__data__/database.db",
operations,
db_file_path=Path("__data__/continued.db"),
)
Without db_file_path, the new run would write to the default __data__/database.db, the file you are restarting from, so EA.restart raises ValueError instead of overwriting it. Pass generation= to continue from an earlier generation. The new file starts with the old run's history up to that generation, under the same ids and generation numbers, so it answers questions about the whole run on its own.
Genotypes
A genotype can be a list or dict of JSON values, or a numpy array, which comes back from the database as the same array, dtype and shape included, and is stored as raw bytes. Other types, such as PyTorch tensors, need a small codec registered with register_codec. docs/genotypes.md explains how genotypes are stored and typed, and examples/a3_numpy_genotypes.py evolves float32 weights.
License
GPL-3.0-or-later, the same as ARIEL, which seachange's code comes from. See LICENSE.
Documentation
Every public class and function has a NumPy-style docstring. The Sphinx sources are in docs/.
Metadata
Release files for seachange 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| seachange-0.1.0.tar.gz | 55.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| seachange-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 117.4 kB
Release files / seachange-0.1.0.tar.gz
| Download URL | seachange-0.1.0.tar.gz |
|---|---|
| Size | 55.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
39acbb3ef428c1ecc118738c7c9726466e88125de3737937018f055a61a875ae
|
|
BLAKE2b-256 checksum How to use checksums |
0c04670f9cd4709ed9c11e6f4f23d1ddcc0f1944dcf4ae778854e66e655d7924
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / seachange-0.1.0-py3-none-any.whl
| Download URL | seachange-0.1.0-py3-none-any.whl |
|---|---|
| Size | 62.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5fd24414ec53fe4445bd1f34419789fbeecc1cdf4d69d182a238a411f6e05c5b
|
|
BLAKE2b-256 checksum How to use checksums |
6c57d549ac954bac5a15302ba85096bbd79459ba9c9cde7b65c18c3d27b29d8c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for seachange 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.