docs: correct disconnected-front and sequencing guidance from compare results
The `compare` harness contradicts two recommendations in the decision trees: - "Disconnected or non-convex front -> AGE-MOEA, KnEA, IBEA" had it backwards. Added KnEA to the ZDT3 table (the disconnected-front benchmark) so the claim is actually exercised: AGE-MOEA and KnEA finish *last and second-last*; IBEA wins, MOEA/D and NSGA-II follow. The trees now split "disconnected" from "non-convex contiguous", lead disconnected with IBEA, and note the geometry-aware methods trail when the front is in pieces. - The book filed Simulated Annealing on permutations as a "one-decision baseline" and led the JSS row with GA. On the harness SA *wins* the FT06 job-shop table and ties for the TSP optimum; SA/Tabu edge out the GA. Reframed SA/Tabu as strong sequencing methods. Also regenerated examples/compare-results.md for the new ZDT3 row. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -412,10 +412,13 @@ START
|
|||||||
│ │ → GA with BitFlipMutation +
|
│ │ → GA with BitFlipMutation +
|
||||||
│ │ a bit-string crossover
|
│ │ a bit-string crossover
|
||||||
│ │
|
│ │
|
||||||
│ ├─ Decision is Vec<usize> (permutation, e.g., TSP)
|
│ ├─ Decision is Vec<usize> (permutation: TSP, JSS, …)
|
||||||
│ │ → Ant Colony (with a distance matrix)
|
│ │ → Ant Colony (TSP, with a distance matrix)
|
||||||
│ │ → Tabu Search (with your own neighbor function)
|
│ │ → Simulated Annealing / Tabu Search (strong on
|
||||||
│ │ → Simulated Annealing with SwapMutation
|
│ │ sequencing — they win the harness TSP and JSS
|
||||||
|
│ │ tables — you supply the neighbour move)
|
||||||
|
│ │ → GA + permutation toolkit (ERX for TSP-shaped
|
||||||
|
│ │ instances)
|
||||||
│ │
|
│ │
|
||||||
│ └─ Custom decision type (a struct, a tree, …)
|
│ └─ Custom decision type (a struct, a tree, …)
|
||||||
│ → Simulated Annealing or Hill Climber
|
│ → Simulated Annealing or Hill Climber
|
||||||
@@ -448,10 +451,14 @@ START
|
|||||||
│ ├─ Want decomposition / weight-vector style
|
│ ├─ Want decomposition / weight-vector style
|
||||||
│ │ → MOEA/D (very fast per generation, scales well)
|
│ │ → MOEA/D (very fast per generation, scales well)
|
||||||
│ │
|
│ │
|
||||||
│ ├─ Disconnected or non-convex front
|
│ ├─ Disconnected front (separate arcs, e.g. ZDT3)
|
||||||
|
│ │ → IBEA (wins ZDT3 hypervolume on the harness;
|
||||||
|
│ │ MOEA/D and NSGA-II follow. Geometry-aware
|
||||||
|
│ │ methods trail when the front is in pieces)
|
||||||
|
│ │
|
||||||
|
│ ├─ Non-convex but *contiguous* front
|
||||||
│ │ → AGE-MOEA (estimates front geometry adaptively)
|
│ │ → AGE-MOEA (estimates front geometry adaptively)
|
||||||
│ │ → KnEA (favors knee points)
|
│ │ → KnEA (favors knee points)
|
||||||
│ │ → IBEA
|
|
||||||
│ │
|
│ │
|
||||||
│ ├─ Want region-based diversity
|
│ ├─ Want region-based diversity
|
||||||
│ │ → PESA-II (grid hyperboxes drive selection)
|
│ │ → PESA-II (grid hyperboxes drive selection)
|
||||||
|
|||||||
@@ -104,9 +104,9 @@ optimizer or with the problem).
|
|||||||
| `Vec<bool>` | [GA][GeneticAlgorithm] + [`BitFlipMutation`] | When bit interactions matter. |
|
| `Vec<bool>` | [GA][GeneticAlgorithm] + [`BitFlipMutation`] | When bit interactions matter. |
|
||||||
| `Vec<usize>` (permutation) | [Ant Colony][AntColonyTsp] | TSP-style with a distance matrix. |
|
| `Vec<usize>` (permutation) | [Ant Colony][AntColonyTsp] | TSP-style with a distance matrix. |
|
||||||
| `Vec<usize>` (permutation) | [GA][GeneticAlgorithm] + [`ShuffledPermutation`] + [`OrderCrossover`] + [`InversionMutation`] | Generic permutation GA; use [`EdgeRecombinationCrossover`] for TSP-shaped instances. |
|
| `Vec<usize>` (permutation) | [GA][GeneticAlgorithm] + [`ShuffledPermutation`] + [`OrderCrossover`] + [`InversionMutation`] | Generic permutation GA; use [`EdgeRecombinationCrossover`] for TSP-shaped instances. |
|
||||||
| `Vec<usize>` (JSS multiset) | [GA][GeneticAlgorithm] + [`ShuffledMultisetPermutation`] + local POX + [`InversionMutation`] | Operation-string encoding; see [Optimize a permutation](./cookbook/permutation.md). |
|
| `Vec<usize>` (JSS multiset) | [Simulated Annealing][SimulatedAnnealing] / [Tabu Search][TabuSearch] with [`InsertionMutation`], or [GA][GeneticAlgorithm] + [`ShuffledMultisetPermutation`] + local POX | Operation-string encoding. On the FT06 harness the local-search pair edges out the GA — see [Optimize a permutation](./cookbook/permutation.md). |
|
||||||
| `Vec<usize>` (permutation) | [Simulated Annealing][SimulatedAnnealing] + [`SwapMutation`] | One-decision baseline. |
|
| `Vec<usize>` (permutation) | [Simulated Annealing][SimulatedAnnealing] + [`InversionMutation`] | Strong on sequencing, not just a baseline — wins the harness's FT06 job-shop table and ties for the TSP optimum. |
|
||||||
| `Vec<usize>` or custom | [Tabu Search][TabuSearch] | You supply the neighbor function. |
|
| `Vec<usize>` or custom | [Tabu Search][TabuSearch] | You supply the neighbor function; consistently near the top on the TSP and JSS tables. |
|
||||||
| Custom struct | [Simulated Annealing][SimulatedAnnealing] / [Hill Climber][HillClimber] | With your own `Variation` impl. |
|
| Custom struct | [Simulated Annealing][SimulatedAnnealing] / [Hill Climber][HillClimber] | With your own `Variation` impl. |
|
||||||
|
|
||||||
heuropt's permutation operator toolkit covers four crossovers
|
heuropt's permutation operator toolkit covers four crossovers
|
||||||
@@ -161,14 +161,24 @@ objectives.
|
|||||||
|
|
||||||
### Disconnected or non-convex front
|
### Disconnected or non-convex front
|
||||||
|
|
||||||
|
A *disconnected* front (separate arcs, like ZDT3) and a *non-convex but
|
||||||
|
contiguous* front are different problems — don't conflate them.
|
||||||
|
|
||||||
|
For a **disconnected** front, [IBEA][Ibea] is the clear pick: on the
|
||||||
|
harness it wins ZDT3 — the disconnected-front benchmark — outright on
|
||||||
|
hypervolume, with [MOEA/D][Moead] and [NSGA-II][Nsga2] close behind.
|
||||||
|
Counter-intuitively the geometry-aware methods below *trail* here:
|
||||||
|
estimating a single front geometry or chasing knee points doesn't help
|
||||||
|
when the front is in pieces (on ZDT3, AGE-MOEA and KnEA finish last).
|
||||||
|
|
||||||
|
For a **non-convex but contiguous** front:
|
||||||
|
|
||||||
[AGE-MOEA][AgeMoea] estimates the front geometry adaptively (the L_p
|
[AGE-MOEA][AgeMoea] estimates the front geometry adaptively (the L_p
|
||||||
parameter `p` is fit from data each generation).
|
parameter `p` is fit from data each generation).
|
||||||
|
|
||||||
[KnEA][Knea] favors knee points — the regions of the front where small
|
[KnEA][Knea] favors knee points — the regions of the front where small
|
||||||
gains in one objective cost large losses in another.
|
gains in one objective cost large losses in another.
|
||||||
|
|
||||||
[IBEA][Ibea] also handles disconnected fronts well.
|
|
||||||
|
|
||||||
### Region-based diversity
|
### Region-based diversity
|
||||||
|
|
||||||
[PESA-II][PesaII] uses grid hyperboxes to drive selection — divide the
|
[PESA-II][PesaII] uses grid hyperboxes to drive selection — divide the
|
||||||
|
|||||||
@@ -60,10 +60,17 @@ dominated gaps between them.
|
|||||||
|
|
||||||
| algorithm | hypervolume ↑ | spacing ↓ | front | ms |
|
| algorithm | hypervolume ↑ | spacing ↓ | front | ms |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| **IBEA** | **126.2072 ± 1.2280** | 0.0164 ± 0.0036 | 48 | 131 |
|
| **IBEA** | **126.2072 ± 1.2280** | 0.0164 ± 0.0036 | 48 | 126 |
|
||||||
| MOEA/D | 125.2413 ± 2.1647 | 0.0198 ± 0.0043 | 92 | 27 |
|
| MOEA/D | 125.2413 ± 2.1647 | 0.0198 ± 0.0043 | 92 | 26 |
|
||||||
| NSGA-II | 123.1826 ± 1.5829 | **0.0092 ± 0.0020** | 98 | 40 |
|
| NSGA-II | 123.1826 ± 1.5829 | **0.0092 ± 0.0020** | 98 | 39 |
|
||||||
| AGE-MOEA | 119.5132 ± 1.2732 | 0.0136 ± 0.0023 | 90 | 171 |
|
| AGE-MOEA | 119.5132 ± 1.2732 | 0.0136 ± 0.0023 | 90 | 170 |
|
||||||
|
| KnEA | 117.2180 ± 0.7027 | 0.0147 ± 0.0049 | 79 | 32 |
|
||||||
|
|
||||||
|
The **geometry-aware methods finish last** on the disconnected front:
|
||||||
|
AGE-MOEA and KnEA both trail the dominance- and decomposition-based
|
||||||
|
methods. Estimating a single front geometry — or chasing knee points —
|
||||||
|
doesn't help when the front is in pieces; IBEA's indicator-based
|
||||||
|
selection wins here.
|
||||||
|
|
||||||
## DTLZ2 (3-obj, dim=12, 30000 evals/run × 10 seeds)
|
## DTLZ2 (3-obj, dim=12, 30000 evals/run × 10 seeds)
|
||||||
|
|
||||||
|
|||||||
@@ -1574,6 +1574,29 @@ fn zdt3_age_moea(seed: u64) -> MoRun {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn zdt3_knea(seed: u64) -> MoRun {
|
||||||
|
let problem = zdt3_problem();
|
||||||
|
let bounds = vec![(0.0, 1.0); ZDT3_DIM];
|
||||||
|
let initializer = RealBounds::new(bounds.clone());
|
||||||
|
let variation = CompositeVariation {
|
||||||
|
crossover: SimulatedBinaryCrossover::new(bounds.clone(), 15.0, 0.5),
|
||||||
|
mutation: PolynomialMutation::new(bounds, 20.0, 1.0 / ZDT3_DIM as f64),
|
||||||
|
};
|
||||||
|
let pop = 100;
|
||||||
|
let config = KneaConfig {
|
||||||
|
population_size: pop,
|
||||||
|
generations: ZDT3_BUDGET / pop,
|
||||||
|
seed,
|
||||||
|
};
|
||||||
|
let mut opt = Knea::new(config, initializer, variation);
|
||||||
|
let t0 = Instant::now();
|
||||||
|
let result = opt.run(&problem);
|
||||||
|
MoRun {
|
||||||
|
front: result.pareto_front,
|
||||||
|
wall_ms: t0.elapsed().as_millis(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// DTLZ1 runners (curated many-obj subset)
|
// DTLZ1 runners (curated many-obj subset)
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -1998,6 +2021,7 @@ fn run_zdt3_comparison() {
|
|||||||
("MOEA/D", zdt3_moead),
|
("MOEA/D", zdt3_moead),
|
||||||
("IBEA", zdt3_ibea),
|
("IBEA", zdt3_ibea),
|
||||||
("AGE-MOEA", zdt3_age_moea),
|
("AGE-MOEA", zdt3_age_moea),
|
||||||
|
("KnEA", zdt3_knea),
|
||||||
];
|
];
|
||||||
let mut rows: Vec<(f64, Vec<String>)> = Vec::new();
|
let mut rows: Vec<(f64, Vec<String>)> = Vec::new();
|
||||||
for (name, runner) in runners {
|
for (name, runner) in runners {
|
||||||
|
|||||||
Reference in New Issue
Block a user