perf(pareto): flatten non_dominated_sort objective buffer (1.29M -> 1.10M instr)
The O(n^2) pair loop reads oriented[j] for every j; with Vec<Vec<f64>> that chased a separate heap allocation per individual. A flat n*m buffer keeps those reads contiguous and sequential in j. non_dominated_sort_2d n=200: 1_288_072 -> 1_096_738 (-15%, 1.17x); n=50 -19%. nsga2 one-generation -5.7%. Combined with the earlier antisymmetry fix, n=200 is down 55% from the original 2.46M. Pure data-layout change -- output bit-identical, all 606 tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+9
-6
@@ -51,11 +51,14 @@ pub fn non_dominated_sort<D>(
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|c| c.evaluation.constraint_violation)
|
.map(|c| c.evaluation.constraint_violation)
|
||||||
.collect();
|
.collect();
|
||||||
let oriented: Vec<Vec<f64>> = population
|
|
||||||
.iter()
|
|
||||||
.map(|c| objectives.as_minimization(&c.evaluation.objectives))
|
|
||||||
.collect();
|
|
||||||
let m = objectives.len();
|
let m = objectives.len();
|
||||||
|
// Flat `n * m` buffer rather than `Vec<Vec<f64>>`: the O(n²) pair loop
|
||||||
|
// reads `oriented[j]` for every `j`, and a contiguous layout keeps those
|
||||||
|
// reads sequential instead of chasing one heap allocation per individual.
|
||||||
|
let mut oriented: Vec<f64> = Vec::with_capacity(n * m);
|
||||||
|
for c in population {
|
||||||
|
oriented.extend_from_slice(&objectives.as_minimization(&c.evaluation.objectives));
|
||||||
|
}
|
||||||
|
|
||||||
let mut dominates: Vec<Vec<usize>> = vec![Vec::new(); n];
|
let mut dominates: Vec<Vec<usize>> = vec![Vec::new(); n];
|
||||||
let mut dominated_by_count: Vec<usize> = vec![0; n];
|
let mut dominated_by_count: Vec<usize> = vec![0; n];
|
||||||
@@ -69,7 +72,7 @@ pub fn non_dominated_sort<D>(
|
|||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
let ai_feasible = feasible[i];
|
let ai_feasible = feasible[i];
|
||||||
let ai_violation = violation[i];
|
let ai_violation = violation[i];
|
||||||
let ai = &oriented[i];
|
let ai = &oriented[i * m..i * m + m];
|
||||||
for j in (i + 1)..n {
|
for j in (i + 1)..n {
|
||||||
let bi_feasible = feasible[j];
|
let bi_feasible = feasible[j];
|
||||||
let bi_violation = violation[j];
|
let bi_violation = violation[j];
|
||||||
@@ -89,7 +92,7 @@ pub fn non_dominated_sort<D>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
(true, true) => {
|
(true, true) => {
|
||||||
let bj = &oriented[j];
|
let bj = &oriented[j * m..j * m + m];
|
||||||
let mut a_better_anywhere = false;
|
let mut a_better_anywhere = false;
|
||||||
let mut b_better_anywhere = false;
|
let mut b_better_anywhere = false;
|
||||||
for k in 0..m {
|
for k in 0..m {
|
||||||
|
|||||||
Reference in New Issue
Block a user