genoxide for Python
The algorithms of genoxide, a Rust library, with fitness functions in Python and numpy:
- genetic algorithms and local search
- differential evolution, CMA-ES and particle swarm optimization
- NSGA-II, NSGA-III, SPEA2, MOEA/D and SMS-EMOA for several objectives
The API reference: tachsin.github.io/genoxide/api/python
import numpy as np
import genoxide as gx
# OneMax: the genome with the most ones
ga = gx.Ga(
gx.Binary(100),
population_size=100,
select=gx.Tournament(3),
crossover=gx.UniformCrossover(),
mutation=gx.BitFlip(rate=0.01),
seed=42,
)
result = ga.run(lambda bits: bits.sum(), target=100, generations=1_000)
print(result.best_fitness, result.generations)
# Rastrigin with CMA-ES and IPOP restarts, a generation per call
def rastrigin(x): # x: a genome per row
return 10 * x.shape[1] + np.sum(x**2 - 10 * np.cos(2 * np.pi * x), axis=1)
cmaes = gx.Cmaes(gx.Real((-5.12, 5.12), length=10), restarts="ipop", objective="minimize", seed=1)
result = cmaes.run(rastrigin, batch=True, target=1e-8, evaluations=500_000)
print(result.best_genome, result.best_fitness)
More in examples/, each the same program in Python and Rust
(python examples/<name>/main.py in the repository), and on the docs site:
- OneMax, a knapsack with a constraint, and N-Queens
- the travelling salesman (TSPLIB berlin52) and job shop scheduling (ft06)
- Rastrigin with CMA-ES and L-SHADE, and the pressure vessel design with constraints
- ZDT1 with NSGA-II, and DTLZ2 with NSGA-III
- XOR neuroevolution with CMA-ES
Install
pip install genoxide
Wheels for CPython 3.10 or later, with numpy:
- Linux: x86_64 and aarch64, glibc and musl
- macOS: Apple silicon and Intel
- Windows: x64
To build from the repository, with Rust and maturin:
cd python
pip install maturin
maturin develop --release
Fitness functions
A fitness function takes a genome as a numpy array:
| Genome | Array |
|---|---|
Binary(length) |
bool |
Integer(bounds, length) |
int64 |
Real(bounds, length) |
float64 |
Permutation(length) |
int64, an ordering of 0 .. length - 1 |
bounds is one pair (low, high) for every gene, with length, or a list of pairs, one per gene.
It returns one of these:
- a number
Noneor NaN, for a solution that can't be scored(score, constraint_violation): a positive violation marks an infeasible solution. Infeasible solutions rank below feasible ones, and among themselves by violation (Deb's rules).
The fitness function must be deterministic: genoxide doesn't evaluate again a child identical to one of its parents.
With batch=True, the function takes a whole generation as a 2-D array, a genome per row. It returns:
- an array of scores, or a tuple of scores and constraint violations (arrays or
(n, 1)columns) - for several objectives, a 2-D array: a row of objective values per genome
It's one call per generation, and none for a generation whose children are all copies of their parents. Vectorized numpy, a GPU or a remote service pays its cost per call once per generation, not once per genome.
With parallel=True, genoxide calls a non-batch function from several threads at once. It pays off when the function releases the GIL (numpy on large arrays, waiting for I/O), or on free-threaded Python.
An exception in the fitness function stops the run, and run raises it. So does Ctrl+C.
Choosing an algorithm
| Problem | Genome | Algorithms, the first preferred |
|---|---|---|
| Yes / no choices (subsets) | Binary |
Ga with UniformCrossover() or PointCrossover(points), and BitFlip |
| An order (tours, sequencing) | Permutation |
LocalSearch, which often beats a GA on permutations; Ga with OrderCrossover() (sequences) or EdgeRecombinationCrossover() (tours) |
| Reals in ranges | Real |
Cmaes; De; Ga with SimulatedBinaryCrossover(eta) and PolynomialMutation(eta) |
| Several objectives | any | Nsga2 for 2 or 3 objectives; Nsga3 or Moead for more |
Cmaesis the strongest general choice for continuous problems with up to a few hundred genes, especially when the genes interact. Its defaults need no tuning. For multimodal functions, addrestarts="ipop"or"bipop".Deoften needs far fewer evaluations than a GA on continuous problems.Psowithring=1explores longer than the default global topology, for multimodal functions.- For smooth problems that need precise answers, the Rust library also has an evolution strategy,
Es.
Algorithms
| Algorithm | Genomes | Settings |
|---|---|---|
Ga |
all | population_size, select, crossover, mutation, crossover_rate (0.9), mutation_rate (1), scheme |
LocalSearch |
all | neighbor (a mutation), neighbors (1), acceptance, restart=(patience, kicks) |
De |
real | population_size (100), l_shade (a budget of evaluations, for L-SHADE) |
Cmaes |
real | population_size, restarts ("ipop", "bipop"), initial_step |
Pso |
real | population_size (needed), ring (neighbors on each side) |
Nsga2 |
all | objectives, population_size, crossover, mutation, crossover_rate (0.9), mutation_rate (1) |
Nsga3 |
all | objectives, reference_directions, crossover, mutation, population_size (the number of reference directions), crossover_rate (1), mutation_rate (1) |
Spea2 |
all | objectives, population_size (the archive's), crossover, mutation, crossover_rate (0.9), mutation_rate (1) |
Moead |
all | objectives, weights (a subproblem each), crossover, mutation, decomposition (Tchebycheff()), neighbors (20), neighbor_mating (0.9), max_replacements (2), crossover_rate (1), mutation_rate (1) |
SmsEmoa |
all | objectives, population_size, crossover, mutation, offspring (population_size), crossover_rate (0.9), mutation_rate (1) |
Single-objective algorithms maximize, or minimize with objective="minimize".
The multi-objective algorithms take objectives=["minimize", "maximize", ...], 2 to 6 of them. Their fitness function returns a sequence of objective values. Their result is the final non-dominated front: front_genomes, front_objectives and front_violations.
A solution that couldn't be scored has NaN objective values and a NaN violation. A single-objective result without a valid solution has a NaN violation.
Nsga2spreads the front by crowding distance, which works poorly beyond 2 or 3 objectives.Nsga3spreads it along reference directions instead.Moeadsolves a single-objective subproblem per weight vector.das_dennis(objectives, divisions)gives evenly spread directions or weights forNsga3andMoead, a row each: 91 for 3 objectives and 12 divisions.Spea2keeps an archive of the best solutions, the non-dominated ones first, truncated by the distance to their nearest neighbors.Nsga2,Nsga3,Spea2andSmsEmoadrop a child that equals a member of the population or an earlier child, and breed another, as pymoo does.eliminate_duplicates=Falsekeeps copies.SmsEmoaremoves the solutions that contribute the least hypervolume, from the last front that fits partly. It costs more per generation thanNsga2: O(N log N) per removal for 2 objectives, O(N²) for 3, O(N³) for 4 and O(N⁴) for 5. For 4 or 5 objectives,Nsga3orMoeadare better choices.
Every algorithm takes a seed. The same seed repeats a run exactly: one genome at a time, in batches or in parallel.
Operators:
- Selection:
Tournament(size),Rank(pressure),Roulette(),StochasticUniversalSampling(),Truncation(fraction),RandomSelection() - Crossover:
- any list genome:
UniformCrossover(),PointCrossover(points),NoCrossover() - real genomes:
SimulatedBinaryCrossover(eta),BlendCrossover(alpha),ArithmeticCrossover() - permutations:
OrderCrossover(),PartiallyMappedCrossover(),CycleCrossover(),EdgeRecombinationCrossover()
- any list genome:
- Mutation:
- binary genomes:
BitFlip(rate=... | count=...) - integer and real genomes:
UniformMutation(rate=... | count=...) - real genomes:
GaussianMutation(sigma, rate=... | count=...),PolynomialMutation(eta, rate=... | count=...) - permutations:
SwapMutation(count),InversionMutation(),InsertionMutation(),ScrambleMutation()
- binary genomes:
- Genetic algorithm schemes:
Generational(elitism)(the default, with 1),SteadyState(replacements),MuPlusLambda(offspring),MuCommaLambda(offspring) - Local search acceptance:
NotWorse()(the default),Improving(),Annealing(initial_temperature, cooling),Tabu(tenure) - MOEA/D decomposition:
Tchebycheff()(the default),Pbi(theta)(penalty-based boundary intersection,theta5 by default).Pbispreads fronts of 3 or more objectives well.
Stopping
run stops at the first of its stop conditions, and needs at least one:
generationsevaluationstarget: a score at least as good (single objective)time: seconds (math.inffor no limit)stagnation: generations without improvement
The result has the condition that stopped it, stop_reason, and the generations, evaluations and seconds it took.
Progress
run(..., on_generation=callback) calls callback after every generation, the initial population (generation 0) included. It runs on the thread that called run. It gets a read-only object:
Progress: thegeneration,evaluations,secondsandbest_fitnessso far (Nonebefore a valid solution)MultiProgress, for a multi-objective algorithm: the same, withfront_size(the number of non-dominated individuals in the population) instead ofbest_fitness
If callback returns False, the run stops with the stop reason "aborted". If it raises an exception, the run stops and run raises it.
def report(progress):
if progress.generation % 100 == 0:
print(progress.generation, progress.evaluations, progress.best_fitness)
result = ga.run(lambda bits: bits.sum(), generations=1_000, on_generation=report)
The Rust library
The package covers a subset of the Rust library. These parts are only in Rust:
- the evolution strategy
Es, with self-adaptive mutation - the island model,
Islands SteadyGaand the asynchronous engine, for evaluations of varying duration- memetic search in
Ga, and initial genomes for a population - operators of your own
- checkpoints, to save and resume a run
- observers: statistics, a hall of fame and reports
- the multi-objective indicators (hypervolume, IGD and others) and test problems
- stop conditions combined with
and, and custom ones - penalty functions for constraints, and the NaN policy: in Python, NaN is always an invalid solution
- advanced settings:
- CMA-ES: a diagonal covariance matrix (sep-CMA-ES) and the initial mean
- PSO: the inertia, the acceleration and the maximum velocity
- DE: the strategy, the control of F and CR, the restarts, and population size reduction other than L-SHADE's
- the rate of
UniformCrossoverand the weight ofArithmeticCrossover
Some names differ:
| Python | Rust |
|---|---|
mutation= |
.mutate(...) |
objective="minimize" |
.minimize(), Objective::Minimize |
Binary(length), Permutation(length) |
Binary::new(len), Permutation::new(len) |
BitFlip(rate=...), BitFlip(count=...) |
BitFlip::per_gene(rate), BitFlip::count(count), and so for the other mutations |
PointCrossover(points) |
PointCrossover::k_point(points) |
MuPlusLambda(offspring), MuCommaLambda(offspring) |
Scheme::MuPlusLambda { lambda }, Scheme::MuCommaLambda { lambda } |
Cmaes(restarts="ipop") |
.restarts(cmaes::Restarts::Ipop) |
Pso(ring=k) |
.topology(pso::Topology::Ring { neighbors: k }) |
De(l_shade=n) |
De::l_shade(real, n) |
Pbi(theta) |
Decomposition::Pbi { theta } |
run(generations=..., time=..., ...) |
Stop::generations(...).or(Stop::time(...)) |
time (seconds) |
Stop::time(Duration) |
result.seconds |
Outcome::elapsed() |
Metadata
Release files for genoxide 0.7.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 | |
|---|---|---|---|
| genoxide-0.7.0.tar.gz | 385.0 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| genoxide-0.7.0-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| genoxide-0.7.0-cp310-abi3-musllinux_1_2_x86_64.whl | CPython 3.10 | abi3 | Linux musl 1.2+ x86-64 | Details |
| genoxide-0.7.0-cp310-abi3-musllinux_1_2_aarch64.whl | CPython 3.10 | abi3 | Linux musl 1.2+ ARM64 | Details |
| genoxide-0.7.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| genoxide-0.7.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| genoxide-0.7.0-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
| genoxide-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl | CPython 3.10 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 16.4 MB
Release files / genoxide-0.7.0.tar.gz
| Download URL | genoxide-0.7.0.tar.gz |
|---|---|
| Size | 385.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ef89136489615a7e63199f02525c1206965bb15a45f666e34cf39c83a6ae3cea
|
|
BLAKE2b-256 checksum How to use checksums |
fd00eeca5adf71387dca7d031d000c9ca0481f726b167546bef01f2e81280e32
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency logRelease files / genoxide-0.7.0-cp310-abi3-win_amd64.whl
| Download URL | genoxide-0.7.0-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 2.5 MB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
1afb427e8b70f40b43a394a26901a1c3ffca6aef1d017fc0a459b47a3cf5e1af
|
|
BLAKE2b-256 checksum How to use checksums |
4536b98e80b73b8a616c2f785a0a19f64327095734002ec341505408203c43f7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency logRelease files / genoxide-0.7.0-cp310-abi3-musllinux_1_2_x86_64.whl
| Download URL | genoxide-0.7.0-cp310-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 2.6 MB |
| Tags | CPython 3.10 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
20549e7e409f642cfadfbe0e669ef76b6e687902f399d90bd2a9fc1f85f71189
|
|
BLAKE2b-256 checksum How to use checksums |
a95200a27797d8376ea5ad615d873f4a72d4568d6f07f5731732b7b7b45d10e9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency logRelease files / genoxide-0.7.0-cp310-abi3-musllinux_1_2_aarch64.whl
| Download URL | genoxide-0.7.0-cp310-abi3-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 2.2 MB |
| Tags | CPython 3.10 Linux musl 1.2+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
024aa0869269e331a46616715b426a65c045ce075778e57e6d61230982c5e122
|
|
BLAKE2b-256 checksum How to use checksums |
e654721722860818881edcb6f29d1e8abeeeda5c26fa071044bbc2ba7752e4a4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency logRelease files / genoxide-0.7.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | genoxide-0.7.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 2.4 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
56b929b59ff718ea8974633dd54ac4eb4b9419c07b738a1dfd2ebfaf002e43b8
|
|
BLAKE2b-256 checksum How to use checksums |
9659e29de524a87e98e0781eb3a9d00b5a58434829dcd0bf59b67422a478d48b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency logRelease files / genoxide-0.7.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | genoxide-0.7.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 2.0 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
9a98406bc975ca57f5ba2e716d36add4fd4f7aa3abbb67ceba0c9b019e74fa7b
|
|
BLAKE2b-256 checksum How to use checksums |
6d54492b8642662124c905a76a5c85fbc2275d397e759f22851c52f9d3d42945
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency logRelease files / genoxide-0.7.0-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | genoxide-0.7.0-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 2.0 MB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
c98d140c908371fa4d7ef651f37e15dcaeee9fd14d08c638dcdd4184e63fadf3
|
|
BLAKE2b-256 checksum How to use checksums |
d32194cfa1dd0cea103c1afb6c461ade64411420bebb582507892ac22d84593c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency logRelease files / genoxide-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl
| Download URL | genoxide-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 2.3 MB |
| Tags | CPython 3.10 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
0ef22a4558ce5a39528c31259a870138adc259a6ef0403442b1fcb33446aa6ea
|
|
BLAKE2b-256 checksum How to use checksums |
d3d3519daac92e8b59315332176bd48a466abe9a11c60a71bf1ee9c7f7b43827
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency log