A plugin-driven bridge between simulation models and multi-objective evolutionary algorithms.
Project description
Optienv
Optienv is a lightweight, simulator‑friendly framework for multi‑objective optimization (MOO). It wraps your external models with a simple CSV interface and lets you run evolutionary algorithms—currently NSGA‑II and NSGA‑III—at scale. It focuses on:
- Reproducible experiments: single‑file per‑seed histories, optional checkpoints/resume, and fixed seeds.
- Simulator integration: CSV adapter that reads variable assignments and writes objective values—no code rewrites inside your model.
- Many‑objective capability: NSGA‑III with reference directions for high‑dimensional objectives (≥ 4).
- Actionable analysis: global Pareto front extraction and normalized hypervolume (HV) computation without a user‑provided reference point, including density control via
--epsilon.
Table of Contents
- Features
- Requirements
- Install
- Core Concepts
- CLI Usage
- NSGA‑III Reference Directions
- Resume / Checkpointing
- Progress Output & Parallel Backends
- Examples
- Troubleshooting
- Roadmap
- License
- Citation / Acknowledgement
Features
- Algorithms
- NSGA‑II: fast non‑dominated sorting + crowding distance (strong baseline).
- NSGA‑III: fast non‑dominated sorting + reference‑direction niching (robust diversity for many objectives).
- CSV model adapter
- Reads
variable_values.csv(decision vector). - Calls your wrapper function (you control the simulation).
- Reads
objective_values.csv(objective values). - Converts maximize objectives to minimization internally (consistent sorting & indicators).
- Reads
- Results management
- One history CSV per seed (
results/history_seed{SEED}.csv) containing all generations. - Optional final CSVs: population, fitness, and non‑dominated mask.
- One history CSV per seed (
- Analysis
front: global non‑dominated set across all seeds +seedprovenance column, optional ε‑box thinning.hypervolume: normalized to [0,1] across all histories; no ref point needed; wide output (one HV column per seed).
- Robustness for Windows/Clusters
- Lean worker processes (no heavy imports) and aggressive cleanup of temp folders (read‑only clearing, retries, background reaper,
atexit).
- Lean worker processes (no heavy imports) and aggressive cleanup of temp folders (read‑only clearing, retries, background reaper,
Requirements
- Python: 3.10+
- OS: Linux / macOS / Windows
- Optional:
pymoo(recommended for HV with > 2 objectives)pip install pymoo
Install
From PyPI
pip install optienv
Tip: Use a virtual environment (e.g.,
python -m venv .venv && source .venv/bin/activateon macOS/Linux or.venv\Scripts\activateon Windows).
For Development
git clone https://github.com/WRHGroup/optienv.git
cd optienv
pip install -e .
Reinstall after code changes to ensure the console script picks them up:
pip install -e .
Core Concepts
CSV Wrapper Contract
Your model’s wrapper (a Python file inside model_dir) must define:
def search_and_apply_variables(model_folder: str) -> None:
...
At runtime, Optienv:
- Copies
model_dirto a temp work folder. - Writes
work/variable_values.csv(columns:Name,Value). - Imports your wrapper from the working copy and calls
search_and_apply_variables(work). - Expects the wrapper to write
work/objective_values.csv(columns:Name,Value). - Converts any maximize objectives to minimization (sign flip).
- Deletes the working copy (unless
--keep-work-on-error).
Tip (Windows/external tools)
Ensure your wrapper waits for external processes to finish and closes file handles:
import subprocess, os
with open(os.devnull, "wb") as devnull:
subprocess.run(["your-sim.exe"], check=True, stdout=devnull, stderr=devnull, close_fds=True)
Run Configuration JSON
A minimal run_sim.json:
{
"model": {
"model_dir": "./toy_model",
"wrapper_file": "wrapper_toy.py",
"variables_csv": "../variable_declaration.csv",
"objectives_csv": "../objective_declaration.csv"
},
"algorithm": {
"population_size": 100,
"generations": 200
}
}
model_dir: folder containing your wrapper file and any model assets.wrapper_file: Python file implementingsearch_and_apply_variables(...).variables_csv: CSV with columnsName,Upper_bound,Lower_bound.objectives_csv: CSV with columnsName,ObjectivewhereObjective∈{minimize,minimise,min,maximize,maximise,max}.
Single‑File History
results/history_seed{SEED}.csv (all generations in one file) with columns:
generation,index,<objective_1>,...,<objective_M>,<x1>,...,<xN>,nd
- Objectives appear first (either your names if
--label-columnswas used or fallbackf0,f1,...). - Variables follow.
ndis a per‑generation non‑dominated mask (1 = non‑dominated among that generation’s population).
CLI Usage
search (NSGA‑II / NSGA‑III)
Run NSGA‑II:
optienv search \
-c path/to/run_sim.json \
--algo nsga2 \
-j 4 --seed 7 \
--label-columns \
--no-save-final-csvs
Run NSGA‑III with reference directions:
optienv search \
-c path/to/run_sim.json \
--algo nsga3 --ref-parts 4 \
-j 4 --seed 7 \
--label-columns --no-save-final-csvs
Key options
--algo:nsga2(default) ornsga3.- NSGA‑III only
--ref-parts <p>: build Das–Dennis simplex‑lattice reference directions (count =binom(M+p-1, p)).--ref-dirs-csv <file>: supply custom reference directions (rows=dirs, cols=#objectives). Rows are auto‑normalized; overrides--ref-parts.
- Parallelism & infra
-j/--max-workers <N>: workers (processes by default).--backend process|thread: usethreadon RAM‑tight nodes.--work-root <dir>: where temp model copies are created.--keep-work-on-error: keep working copy if a failure occurs.
- Outputs
--label-columns: write objective/variable names as headers.--no-save-final-csvs: only write the single history file.
- Resume/checkpoints
--checkpoint-every <N>: write a checkpoint every N generations.--checkpoint-path <file>: where to store the checkpoint (defaultresults/checkpoint.npz).--resume-latest/--resume-from <file>: continue from a checkpoint.
front
Compute a global non‑dominated set across all results/history*.csv:
optienv front
# → results/pareto_front_all.csv
- Automatically converts objective sense using your declaration (if available).
- Adds a
seedcolumn (provenance). --epsilon <eps>: optional ε‑box thinning to control density (e.g.,0.01).
hypervolume (normalized, wide output)
Compute normalized HV per generation for each seed, and write a wide CSV (one HV column per seed):
optienv hypervolume
# → results/hypervolume.csv
# columns: generation, seed7, seed11, ...
- No reference point needed: objectives are first converted to minimization and normalized to [0,1] using global min/max across all histories; HV uses a fixed ref (r=\mathbf{1}).
--epsilon <eps>: optionally thin each generation’s front first (speeds up HV, smoother curves). Try0.01.
For objectives > 2, install
pymooto enable the HV indicator. Without it, a 2‑D fallback is used.
NSGA‑III Reference Directions
NSGA‑III uses reference‑direction niching (instead of crowding distance) to maintain a uniform spread across the Pareto front—especially important for many objectives.
- Default generation: Das–Dennis simplex‑lattice with
--ref-parts p. Number of directions: [ \binom{M+p-1}{p} ] - Best practice: population size ≈ number of reference directions (≈ one survivor per niche).
- High‑dimensional setups (e.g., (M\ge 6)):
- Keep
--ref-partssmall (e.g., 3–4), or - Provide a custom
--ref-dirs-csvwith your desired count and distribution (e.g., 100–300 well‑spaced directions).
- Keep
Resume / Checkpointing
Enable checkpoints during a run:
optienv search ... --checkpoint-every 1 --checkpoint-path results/checkpoint.npz
Resume later:
# Resume from default checkpoint
optienv search ... --resume-latest
# Or resume from a specific path
optienv search ... --resume-from path/to/checkpoint.npz
Checkpoints store generation index, population, fitness, RNG state, variable/objective names, bounds, history path, and model_dir—so resuming is safe and consistent.
Progress Output & Parallel Backends
During evaluation you’ll see:
[search] Gen 5/50 – evaluating 126 candidates (workers=8, backend=process)...
completed: 63/126 ( 50%) elapsed: 00:01:12
completed: 126/126 (100%) elapsed: 00:02:21
[search] Gen 5 done in 00:02:21
--backend process(default) leverages multiple CPUs safely for external simulators.--backend threadcan reduce memory overhead on RAM‑constrained Windows nodes.
Examples
3‑Objective Toy
Structure:
examples/toy_3obj/
├─ toy_model/
│ └─ wrapper_toy.py
├─ variable_declaration.csv
├─ objective_declaration.csv
└─ run_sim_example.json
Run:
cd examples/toy_3obj
# NSGA‑II
optienv search -c run_sim_example.json \
--algo nsga2 -j 2 --seed 7 --label-columns --no-save-final-csvs
# NSGA‑III
optienv search -c run_sim_example.json \
--algo nsga3 --ref-parts 8 -j 2 --seed 7 --label-columns --no-save-final-csvs
# Global front and HV
optienv front --epsilon 0.02
optienv hypervolume
6‑Objective Toy (NSGA‑III vs NSGA‑II)
Structure:
examples/toy_6obj/
├─ toy_model/
│ └─ wrapper_toy6.py
├─ variable_declaration.csv
├─ objective_declaration.csv
└─ run_sim_example.json
For M=6, --ref-parts 4 ⇒ 126 reference directions; match pop≈126 for NSGA‑III:
cd examples/toy_6obj
# NSGA‑II baseline
optienv search -c run_sim_example.json \
--algo nsga2 -j 4 --seed 7 --label-columns --no-save-final-csvs
# NSGA‑III with matched pop size (edit JSON or override before running)
# Example using jq to set population to 126:
jq '.algorithm.population_size=126' run_sim_example.json > run_sim_example_126.json
optienv search -c run_sim_example_126.json \
--algo nsga3 --ref-parts 4 -j 4 --seed 7 --label-columns --no-save-final-csvs
# Compare HV across seeds/generations
optienv hypervolume
You should see NSGA‑III achieve higher normalized HV and better spread in 6 objectives for a similar evaluation budget.
Troubleshooting
-
Temp model copies persist on Windows
- We clear read‑only flags and retry with exponential backoff; a background reaper thread and
atexitattempt final cleanup. - Ensure your wrapper does not
chdir, closes all file handles, and blocks for child processes to finish (subprocess.run(..., check=True, close_fds=True)).
- We clear read‑only flags and retry with exponential backoff; a background reaper thread and
-
Many‑objective HV errors
- Install
pymoofor HV in ≥ 3 objectives:pip install pymoo
- Install
-
Resuming with changed CSVs
- The checkpoint validates variables, objectives, and bounds. If you changed them, start a fresh run.
-
NSGA‑III population vs reference directions
- It’s common to set
population_size ≈ #reference_directions. If they differ you’ll get a note, but the run proceeds.
- It’s common to set
Roadmap
- More MOEAs: MOEA/D, IBEA, SMS‑EMOA (HV‑based survival).
- Reference‑direction factories (Riesz‑energy, multi‑layer designs) directly in the CLI.
- Rich plots & PDF reports.
- Surrogate‑assisted runs for expensive simulators.
License
MIT — see LICENSE.
Citation / Acknowledgement
If Optienv helps your research or engineering work, please cite or acknowledge it. This greatly helps the project grow and justifies continued development.
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 optienv-0.1.1.tar.gz.
File metadata
- Download URL: optienv-0.1.1.tar.gz
- Upload date:
- Size: 43.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ba71e548399bef296bbbc7ebb0e8d40de277362773f636503edab716e1668f86
|
|
| MD5 |
a2aa6db65d7f2ed587f6355ed0a577b7
|
|
| BLAKE2b-256 |
7d92835ebc15733c05eb39c247f48ab73b6c5aafc243890c6b792b34c7cad516
|
File details
Details for the file optienv-0.1.1-py3-none-any.whl.
File metadata
- Download URL: optienv-0.1.1-py3-none-any.whl
- Upload date:
- Size: 41.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eeccd4cd48162da52d8b75515f2942ed0f91869b494f934d5ce7ce568f042c11
|
|
| MD5 |
38d5ad3ec214e624bed59f9b47576294
|
|
| BLAKE2b-256 |
f779a64d933c5a7b1a0e3ff5044f2b22aa4040de922348f8f0502865843dd9f6
|