optimization-multi-objective
Description
Multi-Objective Optimization: Custom Evolutionary Strategy Design
Research Question
Design a novel multi-objective evolutionary algorithm (MOEA) strategy that achieves better convergence, diversity, and spread on standard benchmark problems than classic approaches like NSGA-II, MOEA/D, and SPEA2.
Background
Multi-objective optimization aims to find a set of Pareto-optimal solutions that represent the best trade-offs among conflicting objectives. Evolutionary algorithms are the dominant approach, differing primarily in three components:
- Parent selection: How to choose individuals for mating (e.g., tournament with crowding distance, reference-vector-based).
- Variation: How to produce offspring via crossover and mutation operators.
- Environmental selection (survival): How to prune the combined parent+offspring pool back to population size (e.g., non-dominated sorting + crowding, decomposition into subproblems, indicator-based selection).
Classic algorithms include:
- NSGA-II (Deb et al., 2002): Non-dominated sorting + crowding distance for diversity.
- MOEA/D (Zhang & Li, 2007): Decomposes the problem into scalar subproblems using weight vectors.
- SPEA2 (Zitzler et al., 2001): Strength-based fitness with density estimation via k-nearest neighbors.
State-of-the-art methods include:
- NSGA-III (Deb & Jain, 2014): Reference-point-based selection for many-objective problems.
- RVEA (Cheng et al., 2016): Angle-penalized distance with adaptive reference vectors.
- AGE-MOEA (Panichella, 2019): Adaptive geometry estimation for survival selection.
There is active research into strategies that combine ideas across these paradigms, adapt to problem geometry, or use novel diversity maintenance mechanisms.
Task
Implement a custom multi-objective evolutionary strategy by modifying the CustomMOEA class in deap/custom_moea.py. You should implement the select, vary, survive, and optionally on_generation methods. The algorithm must work for both 2-objective and 3-objective problems.
Interface
class CustomMOEA:
def __init__(self, pop_size, n_obj, n_var, bounds, cx_eta=20.0, mut_eta=20.0, mut_prob=None):
"""Initialize the MOEA with problem parameters."""
def select(self, population: list, k: int) -> list:
"""Select k parents from the population for mating.
Returns: list of k selected individuals."""
def vary(self, parents: list) -> list:
"""Apply crossover and mutation to produce offspring.
Returns: list of offspring (fitness invalidated)."""
def survive(self, population: list, offspring: list) -> list:
"""Environmental selection: choose pop_size individuals from combined pool.
Returns: list of pop_size individuals for next generation."""
def on_generation(self, gen: int, population: list):
"""Optional per-generation callback for adaptive strategies."""
Individual interface:
ind.fitness.values-> tuple of objective values (all minimized)ind.fitness.dominates(other.fitness)-> boolind.fitness.valid-> bool (True if evaluated)
Available DEAP utilities:
tools.sortNondominated(pop, k)-> list of frontstools.selTournamentDCD(pop, k)-> tournament selection (needs crowding dist)tools.selNSGA3(pop, k, ref_points)-> NSGA-III selectiontools.cxSimulatedBinaryBounded(ind1, ind2, eta, low, up)-> SBX crossovertools.mutPolynomialBounded(ind, eta, low, up, indpb)-> polynomial mutationtools.uniform_reference_points(nobj, p)-> generate reference pointscompute_crowding_distance(individuals)-> sets.fitness.crowding_distget_nondominated(population)-> first non-dominated front
Evaluation
Evaluated on four benchmark problems (run with multiple seeds):
- ZDT1 (2D objectives, convex front, 30 variables, 200 generations)
- ZDT3 (2D objectives, disconnected front, 30 variables, 200 generations)
- DTLZ2 (3D objectives, spherical front, 12 variables, 250 generations)
- DTLZ1 (3D objectives, linear front with many local fronts, 7 variables, 400 generations)
Three metrics are reported:
- Hypervolume (HV): Volume of objective space dominated by the Pareto front approximation. Higher is better.
- Inverted Generational Distance (IGD): Average distance from true Pareto front points to nearest found solution. Lower is better.
- Spread: Uniformity of the Pareto front approximation. Lower is better.
Code
1"""2Multi-Objective Optimization — Custom Evolutionary Strategy Template34This script runs a complete multi-objective evolutionary algorithm on standard5benchmark problems (ZDT/DTLZ). The agent should implement the custom selection6and variation strategy in the CustomMOEA class.78Usage:9python deap/custom_moea.py --problem zdt1 --seed 42 --output-dir ./out10"""1112import argparse13import json14import math15import os
Results
| Model | Type | hv zdt1 ↑ | igd zdt1 ↓ | spread zdt1 ↑ | hv zdt3 ↑ | igd zdt3 ↓ | spread zdt3 ↑ | hv dtlz2 ↑ | igd dtlz2 ↓ | spread dtlz2 ↑ | hv dtlz1 ↑ | igd dtlz1 ↓ | spread dtlz1 ↑ |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| agemoea | baseline | 0.863 | 0.008 | 0.583 | 1.316 | 0.008 | 0.765 | 2.572 | 0.091 | 0.519 | 0.957 | 0.025 | 2.158 |
| moead | baseline | 0.863 | 0.010 | 0.507 | 1.321 | 0.010 | 0.940 | 2.737 | 0.076 | 0.846 | 0.953 | 0.034 | 4.408 |
| nsga2 | baseline | 0.868 | 0.005 | 0.343 | 1.326 | 0.006 | 0.566 | 2.741 | 0.065 | 0.653 | 0.970 | 0.027 | 0.904 |
| nsga3 | baseline | 0.869 | 0.004 | 0.287 | 1.323 | 0.006 | 0.621 | 2.790 | 0.052 | 0.621 | 0.973 | 0.020 | 0.648 |
| rvea | baseline | 0.865 | 0.006 | 0.429 | 1.316 | 0.009 | 0.603 | 2.789 | 0.055 | 0.383 | 0.963 | 0.050 | 1.429 |
| spea2 | baseline | 0.868 | 0.005 | 0.149 | 1.324 | 0.005 | 0.426 | 2.781 | 0.050 | 0.106 | 0.974 | 0.018 | 0.138 |
| anthropic/claude-opus-4.6 | vanilla | 0.868 | 0.005 | 0.326 | 1.324 | 0.005 | 0.533 | 2.755 | 0.054 | 0.239 | 0.971 | 0.021 | 7.224 |
| deepseek-reasoner | vanilla | 0.869 | 0.005 | 0.412 | 1.328 | 0.005 | 0.544 | 2.788 | 0.055 | 0.626 | 0.974 | 0.020 | 0.591 |
| google/gemini-3.1-pro-preview | vanilla | 0.869 | 0.005 | 0.348 | 1.325 | 0.006 | 0.706 | 2.790 | 0.070 | 0.541 | 0.968 | 0.020 | 0.201 |
| openai/gpt-5.4-pro | vanilla | 0.868 | 0.005 | 0.390 | 1.324 | 0.005 | 0.480 | 2.782 | 0.052 | 0.266 | 0.974 | 0.018 | 0.224 |
| qwen3.6-plus:free | vanilla | 0.560 | 0.322 | 1.834 | 0.706 | 0.647 | 1.607 | 2.155 | 0.551 | 7.676 | 0.606 | 0.174 | 7.678 |
| anthropic/claude-opus-4.6 | agent | 0.868 | 0.005 | 0.326 | 1.324 | 0.005 | 0.533 | 2.791 | 0.052 | 0.562 | 0.972 | 0.023 | 0.810 |
| deepseek-reasoner | agent | 0.869 | 0.005 | 0.420 | 1.327 | 0.006 | 0.526 | 2.204 | 0.305 | 1.417 | 0.578 | 0.202 | 0.987 |
| google/gemini-3.1-pro-preview | agent | 0.000 | 2.359 | 1.822 | 0.000 | 2.212 | 1.818 | 1.113 | 0.472 | 1.606 | 0.000 | 41.869 | 2.485 |
| openai/gpt-5.4-pro | agent | 0.869 | 0.005 | 0.290 | 1.321 | 0.006 | 0.464 | 2.794 | 0.047 | 0.237 | 0.974 | 0.018 | 0.205 |
| qwen3.6-plus:free | agent | 0.869 | 0.005 | 0.363 | 1.327 | 0.006 | 0.587 | 2.791 | 0.050 | 0.448 | 0.974 | 0.018 | 0.418 |