genetic_algorithms 3.0.0

Library for solving genetic algorithm problems
Documentation
# 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

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `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

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `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

| Factor | MOEA/D | 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