# MOEA/D
> Decomposition-based Multi-Objective Evolutionary Algorithm that decomposes a MOP into scalar sub-problems using weight vectors.
## Description
MOEA/D (Zhang & Li 2007) decomposes a multi-objective problem into N scalar sub-problems using weight vectors. Each sub-problem maintains its own solution and a **neighbourhood** of similar weight vectors. Offspring are generated by selecting two parents from the neighbourhood, applying crossover and mutation, and then competing only against neighbouring sub-problems via **Tchebycheff** or **PBI** scalarization. An ideal point `z*` tracks the best value found for each objective.
Weight vectors are auto-generated via the Das-Dennis simplex lattice or user-supplied.
Per generation, MOEA/D:
1. Iterates all N sub-problems in order.
2. For each sub-problem i:
a. Randomly pick two parents from `neighbourhood[i]`.
b. Apply crossover + mutation to produce one offspring.
c. Evaluate offspring objectives.
d. Update ideal point `z*` (per-objective minimum).
e. Walk `neighbourhood[i]` — if the offspring's scalarised value is better than the current solution for neighbour j, replace it (up to `max_neighbor_replacements`).
3. Post-hoc non-dominated sort on the final population to extract the Pareto front.
MOEA/D does NOT use Pareto ranking for selection — it is a decomposition-based approach that is often faster than Pareto-based methods.
## When to Use
- **Problem type:** Multi-objective (2+ objectives)
- **Number of objectives:** 2+
- **Variable type:** Continuous (real-valued), binary
- **Key strength:** Computationally efficient — no expensive non-dominated sort inside the inner sub-problem loop. Parallelisable via sub-problem distribution.
- **Key weakness:** Quality depends on the distribution of weight vectors. If the Pareto front does not align with the weight grid, coverage may be uneven.
## Quick Reference
### Mandatory Parameters
| `num_objectives` | `usize` | `3` | Number of objectives. |
| `population_size` | `usize` | `100` | Population size (one per sub-problem). |
| `max_generations` | `usize` | `200` | Maximum generations. |
| `init_fn` | `Fn` | — | Chromosome initialization function. |
| `objective_fns` | `Vec<ObjectiveFn>` | — | One closure per objective. |
### Optional Parameters
| `objective_directions` | `Vec<ObjectiveDirection>` | All `Minimize` | Per-objective Min/Max. |
| `scalarization` | `ScalarizationFn` | `Tchebycheff` | Tchebycheff or PBI with penalty theta. |
| `neighborhood_size` | `usize` | `20` | T — number of neighbours per sub-problem. |
| `max_neighbor_replacements` | `usize` | `2` | Max replacements per offspring. |
| `ga_config` | `GaConfiguration` | `Default` | GA operators, limits, RNG seed. |
| `observer` | `MoeaDObserver<U>` | `None` | Lifecycle observer. |
## Complete Example
```rust,ignore
use genetic_algorithms::chromosomes::Range as RangeChromosome;
use genetic_algorithms::configuration::GaConfiguration;
use genetic_algorithms::genotypes::Range as RangeGenotype;
use genetic_algorithms::initializers::range_random_initialization;
use genetic_algorithms::moead::MoeaDGa;
use genetic_algorithms::moead::configuration::{MoeaDConfiguration, ScalarizationFn};
use genetic_algorithms::operations::{Crossover, Mutation};
type MyChromosome = RangeChromosome<f64>;
let moead_config = MoeaDConfiguration::new()
.with_num_objectives(3)
.with_population_size(91)
.with_max_generations(300)
.with_weight_vectors_auto(12)
.with_scalarization(ScalarizationFn::Tchebycheff)
.with_neighborhood_size(20)
.with_max_neighbor_replacements(2);
let ga_config = GaConfiguration::default()
.with_crossover_method(Crossover::Sbx)
.with_mutation_method(Mutation::Polynomial);
let alleles = vec![RangeGenotype::new(0, vec![(0.0, 1.0)], 0.0_f64)];
let alleles_clone = alleles.clone();
let mut moead = MoeaDGa::<MyChromosome>::new(moead_config, ga_config)
.with_initialization_fn(move |n, _, _| {
range_random_initialization(n, Some(&alleles_clone), Some(false))
})
.with_objective_fns(vec![
Box::new(|dna: &[RangeGenotype<f64>]| -> f64 {
(0..dna.len()).map(|i| dna[i].value).sum::<f64>()
}),
Box::new(|dna: &[RangeGenotype<f64>]| -> f64 {
(0..dna.len()).map(|i| (dna[i].value - 1.0).powi(2)).sum::<f64>()
}),
Box::new(|dna: &[RangeGenotype<f64>]| -> f64 {
(0..dna.len()).map(|i| (dna[i].value - 0.5).powi(2)).sum::<f64>()
}),
])
.build()
.expect("Valid MOEA/D configuration");
let pareto_front = moead.run().expect("MOEA/D run failed");
println!("Front size: {}", pareto_front.len());
```
## Configuration Tips
- The number of weight vectors (and thus sub-problems) is determined by `with_weight_vectors_auto(p)` or custom. The population_size should equal the number of weight vectors.
- `Tchebycheff` works well for most problems. Use `Pbi` with `theta = 5.0` when the Pareto front has sharp corners or is dominated by a single objective.
- `neighborhood_size` (T) controls exploitation vs exploration: small T means more local competition (faster convergence); large T means more information sharing (better diversity).
- The final Pareto front is extracted via post-hoc non-dominated sort — the algorithm itself runs decomposition-based selection.
## When to Choose This vs NSGA-III
| Mechanism | Weight-vector decomposition | Reference-point niche preservation |
| Objectives | 2+ | 3+ (many-objective) |
| Selection | Scalarization + neighborhood | Niche preservation |
| Efficiency | No sort in sub-problem loop | Normalize + associate per generation |
| Pareto front | Even coverage if weights align | Uniform reference coverage |
| Robustness | Needs aligned weight vectors | More robust to front shape |
## References
- Zhang, Q., & Li, H. (2007). MOEA/D: A multiobjective evolutionary algorithm based on decomposition. _IEEE Trans. on Evolutionary Computation_, 11(6), 712-731.
## See Also
- [NSGA-III](nsga3.md) — Reference-point based alternative for 3+ objectives
- [Multi-Objective Concepts](multi_objective.md) — Shared MO primitives and quality indicators
- [Engines Overview](engines.md) — Full engine decision matrix
- [docs.rs/genetic_algorithms::moead](https://docs.rs/genetic_algorithms/latest/genetic_algorithms/moead/index.html) — Module API reference