Evolutionary optimizer with NOMAD local search
Project description
Evo‑NOMAD
Evo‑NOMAD is a flexible evolutionary optimizer that couples global search (crossover + mutation) with local, derivative-free refinement via the NOMAD solver, exposed through PyNomad.
Why Evo-NOMAD?
- Derivative‑free continuous control – no action discretisation, no back‑prop through time; handles dense recurrence gracefully.
- Prior‑aware search – starts from a biological connectome (or any strong prior).
- Pure mode: many tiny edits → minimal drift.
- Hybrid mode: < 50 edits → structural fidelity.
- Embarrassingly parallel – flip on Ray to scale linearly with CPU cores.
Installation
pip install EVO-NOMAD
# Development version (clone + editable install)
git clone https://github.com/greenfire0/Evo-NOMAD.git
cd Evo-NOMAD
pip install -e .[ray] # optional: Ray for parallel NOMAD calls
Requirements: Python >= 3.9 · NumPy >= 1.23 · tqdm · PyNomad >= 0.9 · (optional: ray)
Quick start
import numpy as np
from EVONOMAD import EVONOMAD
obj = lambda x: -np.sum(x**2) # maximise => global optimum at x = 0
opt = EVONOMAD(
"pure", # or "hybrid"
population_size=32,
dimension=10,
objective_fn=obj,
subset_size=5,
bounds=0.2,
max_bb_eval=100,
n_mutate_coords=2,
)
best_x, best_fit = opt.run(generations=100)
print(f"Best fitness: {best_fit:.4f}")
API
EVONOMAD(
optimizer_type: Literal["pure", "hybrid"],
population_size: int,
dimension: int,
objective_fn: Callable[[np.ndarray], float],
subset_size: int = 20,
bounds: float = 0.1,
max_bb_eval: int = 200,
n_elites: int | None = None,
n_mutate_coords: int = 5,
crossover_rate: float = 0.5,
crossover_type: Literal["uniform", "fitness"] = "uniform",
crossover_exponent: float = 1.0,
init_pop: np.ndarray | None = None,
init_vec: np.ndarray | None = None,
low: float = -1.0,
high: float = 1.0,
use_ray: bool | None = None,
seed: int | None = None,
)
Methods
Evo‑NOMAD offers two training strategies that differ only in when and how NOMAD is invoked within the evolutionary loop.
Pure mode
Every generation, each individual in the population is passed to NOMAD for local refinement:
- Slice selection – Pick
subset_sizecoordinates at random (≤ 49, per NOMAD’s convergence guarantees). - Local search – Run PyNomad with a ±
boundshyper‑rectangle around that slice and a budget ofmax_bb_evalevaluations. - Replacement – If the refined individual improves its fitness, it replaces the original.
- Reproduction – Select the top
n_elitesby fitness, then fill the rest of the population via fitness‑proportional crossover (probabilitycrossover_rate) followed by random‑reset mutation (n_mutate_coordscoordinates).
Pure mode tends to make many small synaptic adjustments, keeping the overall L2 distance to the original connectome low while steadily improving reward.
Hybrid mode
An evolutionary mutation proposes a sparse change‑set first; NOMAD then fine‑tunes only those altered weights:
- Mutation – Each offspring mutates a random subset of weights (usually < 50).
- Targeted NOMAD – If the diff mask is novel and < 50 coords, run PyNomad only on that mask.
- Evaluation & elitism – Update fitness, retain best individuals, proceed with crossover/mutation.
Hybrid mode yields comparable rewards to Pure mode while changing far fewer synapses – ideal when biological plausibility demands minimal rewiring.
Key hyper‑parameters (shared):
| name | effect |
|---|---|
subset_size |
# parameters NOMAD refines per call (≤ 49) |
bounds |
half‑width of the NOMAD search box |
max_bb_eval |
NOMAD evaluations per call |
n_mutate_coords |
coordinates reset per mutation |
Testing
pip install -e .[dev] # includes pytest, ruff, black, etc.
pytest -q # run smoke + reproducibility tests
Contributing
- Fork + create a feature branch
- Run
pre-commit install - Add unit tests for new behavior
- PR + short summary of the change
License
MIT License — see LICENSE file
Acknowledgements
- Hi my name is miles, I hope you enjoy these algorithms and optimize some cool shit using them <3
- PyNomad
- NOMAD team at Polytechnique Montréal / GERAD
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file evonomad-0.1.1.tar.gz.
File metadata
- Download URL: evonomad-0.1.1.tar.gz
- Upload date:
- Size: 31.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
41572359836dceaf302764be8276fd3699a3922d6ac58a1db63ca0dd6701cc90
|
|
| MD5 |
d2a3298710ff4960680d6b5093dfc536
|
|
| BLAKE2b-256 |
9f8561678dcd706ea45daeb2713e548e8af38fc3ee6552e063c6d1cbc765f687
|
File details
Details for the file evonomad-0.1.1-py3-none-any.whl.
File metadata
- Download URL: evonomad-0.1.1-py3-none-any.whl
- Upload date:
- Size: 29.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
64f599f4a2aac4dbe5e3b0309517910ef41e252b736742bdb198bf8bed045801
|
|
| MD5 |
6e722857d701f6f0bc8fa101f024e4b2
|
|
| BLAKE2b-256 |
953f99d15df6fa68ee64be37c5eef1274ab395371f8f7123811aef377ea98738
|