Skip to content

Commit 9c45ad6

Browse files
committed
update README.md
1 parent 9f8b708 commit 9c45ad6

1 file changed

Lines changed: 84 additions & 64 deletions

File tree

README.md

Lines changed: 84 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,39 @@
11
# NSGA‑II Rust‑Core
22

3-
A Rust implementation of the NSGA‑II multi‑objective evolutionary algorithm. The crate provides
4-
non‑dominated sorting, crowding distance, simulated binary crossover, polynomial mutation, and
5-
tournament selection. Objective evaluation and dominance comparisons run in parallel through Rayon.
6-
Constraint handling is supported via the `Problem` trait, where infeasible solutions are
7-
automatically ranked below feasible ones based on total violation. Per‑generation Pareto front
8-
snapshots, hypervolume indicator tracking, and convergence‑based early stopping are available
9-
through `RunResult`. Algorithm parameters are configured through a builder‑style API.
3+
A high‑performance Rust implementation of the NSGA‑II multi‑objective evolutionary algorithm.
4+
The crate provides:
5+
6+
- fast non‑dominated sorting
7+
- crowding distance
8+
- simulated binary crossover (SBX)
9+
- polynomial mutation
10+
- tournament selection
11+
- constraint handling
12+
- strict and auto‑adjusting hypervolume
13+
- IGD (Inverted Generational Distance)
14+
- per‑generation Pareto snapshots
15+
- early stopping
16+
- reproducible runs via optional RNG seeding
17+
18+
Objective evaluation and dominance checks run in parallel through Rayon.
19+
Algorithm parameters are configured through a builder‑style API.
1020

1121
---
1222

1323
## Modules
1424

15-
- `problem` — the `Problem` trait and built‑in problems
16-
- `evolve`the NSGA‑II engine and `RunResult`
17-
- `sort` — non‑dominated sorting and crowding distance
18-
- `data` — core data structures
19-
- `metrics`hypervolume indicator
25+
- `problem` — the `Problem` trait and built‑in problems
26+
- `evolve` — NSGA‑II engine and `RunResult`
27+
- `sort` — non‑dominated sorting and crowding distance
28+
- `data` — core data structures
29+
- `metrics`strict HV, auto HV, IGD
2030

2131
---
2232

2333
## Usage
2434

2535
### Built‑in Schaffer problem
36+
2637
```rust
2738
use rs_nsga2::evolve::Evolution;
2839
use rs_nsga2::problem::Schaffer;
@@ -37,6 +48,7 @@ fn main() {
3748
```
3849

3950
### Custom problem
51+
4052
```rust
4153
use rs_nsga2::evolve::Evolution;
4254
use rs_nsga2::problem::Problem;
@@ -64,6 +76,7 @@ fn main() {
6476
```
6577

6678
### Constrained problem
79+
6780
```rust
6881
use rs_nsga2::evolve::Evolution;
6982
use rs_nsga2::problem::Problem;
@@ -80,8 +93,7 @@ impl Problem for ConstrainedProblem {
8093
vec![x[0], x[1]]
8194
}
8295
fn constraint_violations(&self, x: &[f64]) -> Vec<f64> {
83-
// x[0] + x[1] >= 2.0, encoded as 2.0 - x[0] - x[1] <= 0
84-
vec![2.0 - x[0] - x[1]]
96+
vec![2.0 - x[0] - x[1]] // x0 + x1 >= 2
8597
}
8698
}
8799

@@ -95,6 +107,7 @@ fn main() {
95107
```
96108

97109
### Hypervolume tracking and early stopping
110+
98111
```rust
99112
use rs_nsga2::evolve::Evolution;
100113
use rs_nsga2::problem::Schaffer;
@@ -106,87 +119,96 @@ fn main() {
106119
.evolve();
107120

108121
println!("Generations completed: {}", result.generations_completed);
109-
110-
for (gen, hv) in result.hypervolume_history.iter().enumerate() {
111-
println!("Generation {}: hypervolume = {:.4}", gen + 1, hv);
112-
}
113-
114-
for ind in &result.pareto_front {
115-
println!("{:?} -> {:?}", ind.features, ind.objectives);
116-
}
117122
}
118123
```
119124

120-
### Hypervolume of an arbitrary front
125+
---
126+
127+
## Metrics
128+
129+
### Strict hypervolume
130+
121131
```rust
122-
use rs_nsga2::metrics::hypervolume_2d;
132+
use rs_nsga2::metrics::hypervolume_2d_strict;
133+
```
123134

124-
fn main() {
125-
let front = vec![
126-
vec![0.1, 3.9],
127-
vec![1.0, 1.0],
128-
vec![2.5, 0.5],
129-
vec![3.8, 0.1],
130-
];
131-
let reference = vec![5.0, 5.0];
132-
let hv = hypervolume_2d(&front, &reference);
133-
println!("Hypervolume: {:.4}", hv);
134-
}
135+
Strict HV requires the reference point to dominate the front.
136+
137+
### Auto‑adjusting hypervolume
138+
139+
```rust
140+
use rs_nsga2::metrics::hypervolume_2d_auto;
135141
```
136142

137-
### Custom algorithm parameters
143+
Auto HV expands the reference point minimally to avoid panics.
144+
145+
### IGD
146+
138147
```rust
139-
use rs_nsga2::evolve::Evolution;
140-
use rs_nsga2::problem::Schaffer;
148+
use rs_nsga2::metrics::igd;
141149

142150
fn main() {
143-
let result = Evolution::new(Schaffer, 100, 300)
144-
.with_crossover_param(15.0)
145-
.with_mutation_param(10.0)
146-
.evolve();
147-
148-
for ind in &result.pareto_front {
149-
println!("{:?} -> {:?}", ind.features, ind.objectives);
150-
}
151+
let true_front = vec![vec![0.0, 1.0], vec![1.0, 0.0]];
152+
let obtained = vec![vec![0.1, 0.9], vec![0.8, 0.2]];
153+
let d = igd(&true_front, &obtained);
154+
println!("IGD: {}", d);
151155
}
152156
```
153157

154158
---
155159

156160
## Algorithm
157161

158-
Each generation applies binary tournament selection, SBX crossover, and polynomial mutation to
159-
produce offspring. Parent and offspring populations are merged, then reduced to the next generation
160-
through non‑dominated sorting and crowding distance ranking. Feasibility is tracked per individual
161-
and incorporated into dominance comparisons — feasible solutions always dominate infeasible ones,
162-
and among infeasible solutions the one with lower total constraint violation is preferred.
162+
Each generation:
163+
164+
1. binary tournament selection
165+
2. SBX crossover
166+
3. polynomial mutation
167+
4. parallel objective evaluation
168+
5. merge parents + offspring
169+
6. fast non‑dominated sort
170+
7. crowding‑distance truncation
171+
172+
Feasible solutions dominate infeasible ones.
173+
Among infeasible solutions, lower total violation is preferred.
163174

164175
---
165176

166177
## RunResult
167178

168-
`evolve()` returns a `RunResult` containing:
179+
`evolve()` returns:
169180

170181
| Field | Description |
171182
|---|---|
172183
| `pareto_front` | Final Pareto‑optimal solutions |
173184
| `history` | Per‑generation Pareto front snapshots |
174-
| `hypervolume_history` | Hypervolume indicator per generation (`NaN` if no reference point set) |
175-
| `generations_completed` | Number of generations actually run (may be less than `num_generations` if early stopping fired) |
185+
| `hypervolume_history` | Strict HV per generation (`NaN` if no reference point) |
186+
| `igd_history` | IGD per generation (`NaN` if no true front) |
187+
| `generations_completed` | Actual number of generations run |
176188

177189
---
178190

179191
## Benchmarks
180192

181-
To measure sorting and evolution performance across population sizes:
193+
The crate includes:
194+
195+
- **evolution** (full NSGA‑II loop)
196+
- **sorting‑only** (fast non‑dominated sort)
197+
- **strict vs auto hypervolume**
198+
- **IGD‑only microbench**
199+
200+
Run all:
201+
182202
```
183203
cargo bench
184204
```
185205

186-
To isolate the impact of parallelisation in `fast_nondominated_sort`:
206+
Run a specific benchmark:
207+
187208
```
188-
RAYON_NUM_THREADS=1 cargo bench --bench sorting
209+
cargo bench --bench igd
189210
cargo bench --bench sorting
211+
cargo bench --bench evolution
190212
```
191213

192214
HTML reports are written to `target/criterion/`.
@@ -195,13 +217,11 @@ HTML reports are written to `target/criterion/`.
195217

196218
## Original authors (Python version)
197219

198-
- Pham Ngo Gia Bao
199-
- Tram Loi Quan
200-
- Quan Thanh Tho
201-
- Akhil Garg
202-
203-
---
220+
- Pham Ngo Gia Bao
221+
- Tram Loi Quan
222+
- Quan Thanh Tho
223+
- Akhil Garg
204224

205225
## Rust port
206226

207-
- Giorgio
227+
- Giorgio

0 commit comments

Comments
 (0)