Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Multi-objective optimization framework. NSGA-II, NSGA-III, MOEA/D, Pareto fronts, constraint handling, benchmarks (ZDT, DTLZ), for engineering design and optimization problems.
.claude/skills/lingxling-pymoo/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 151% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 129% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 126% | 0% |
| case-23 | ✗→✓ | ▲ Improved | 143% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 205% | 0% |
Pymoo is a comprehensive Python framework for optimization with emphasis on multi-objective problems. Solve single and multi-objective optimization using state-of-the-art algorithms (NSGA-II/III, MOEA/D, SPEA2), benchmark problems (ZDT, DTLZ), customizable genetic operators, and multi-criteria decision making methods. Excels at finding trade-off solutions (Pareto fronts) for problems with conflicting objectives. Current stable release: pymoo 0.6.1.6 (November 2025).
bashuv pip install pymoo
For reproducible environments, pin a version: uv pip install "pymoo==0.6.1.6".
Dependencies: NumPy (2.x compatible since 0.6.1.3), SciPy, matplotlib (visualization). Autograd is optional for gradient-based features (since 0.6.1.3).
Documentation: https://pymoo.org/ — LLM-friendly index: https://pymoo.org/llms.txt
This skill should be used when:
Pymoo uses a consistent minimize() function for all optimization tasks:
pythonfrom pymoo.optimize import minimize result = minimize( problem, # What to optimize algorithm, # How to optimize termination, # When to stop seed=1, verbose=True )
Result object contains:
result.X: Decision variables of optimal solution(s)result.F: Objective values of optimal solution(s)result.G: Constraint violations (if constrained)result.algorithm: Algorithm object with historyPymoo supports three problem definition styles:
Problem: Vectorized — _evaluate receives a batch of solutions (matrix)ElementwiseProblem: One solution per call — recommended for custom problems and parallel evaluationFunctionalProblem: Define objectives and constraints as separate functions without subclassingSingle-objective: One objective to minimize/maximize Multi-objective: 2-3 conflicting objectives → Pareto front Many-objective: 4+ objectives → High-dimensional Pareto front Constrained: Objectives + inequality/equality constraints Mixed-variable: Continuous, integer, binary, and categorical variables in one problem Dynamic: Time-varying objectives or constraints
When: Optimizing one objective function
Steps:
Example:
pythonfrom pymoo.algorithms.soo.nonconvex.ga import GA from pymoo.problems import get_problem from pymoo.optimize import minimize # Built-in problem problem = get_problem("rastrigin", n_var=10) # Configure Genetic Algorithm algorithm = GA( pop_size=100, eliminate_duplicates=True ) # Optimize result = minimize( problem, algorithm, ('n_gen', 200), seed=1, verbose=True ) print(f"Best solution: {result.X}") print(f"Best objective: {result.F[0]}")
See: scripts/single_objective_example.py for complete example
When: Optimizing 2-3 conflicting objectives, need Pareto front
Algorithm choice: NSGA-II (standard for bi/tri-objective)
Steps:
Example:
pythonfrom pymoo.algorithms.moo.nsga2 import NSGA2 from pymoo.problems import get_problem from pymoo.optimize import minimize from pymoo.visualization.scatter import Scatter # Bi-objective benchmark problem problem = get_problem("zdt1") # NSGA-II algorithm algorithm = NSGA2(pop_size=100) # Optimize result = minimize(problem, algorithm, ('n_gen', 200), seed=1) # Visualize Pareto front plot = Scatter() plot.add(result.F, label="Obtained Front") plot.add(problem.pareto_front(), label="True Front", alpha=0.3) plot.show() print(f"Found {len(result.F)} Pareto-optimal solutions")
See: scripts/multi_objective_example.py for complete example
When: Optimizing 4 or more objectives
Algorithm choice: NSGA-III (designed for many objectives)
Key difference: Must provide reference directions for population guidance
Steps:
Example:
pythonfrom pymoo.algorithms.moo.nsga3 import NSGA3 from pymoo.problems import get_problem from pymoo.optimize import minimize from pymoo.util.ref_dirs import get_reference_directions from pymoo.visualization.pcp import PCP # Many-objective problem (5 objectives) problem = get_problem("dtlz2", n_obj=5) # Generate reference directions (required for NSGA-III) ref_dirs = get_reference_directions("das-dennis", n_obj=5, n_partitions=12) # Configure NSGA-III algorithm = NSGA3(ref_dirs=ref_dirs) # Optimize result = minimize(problem, algorithm, ('n_gen', 300), seed=1) # Visualize with Parallel Coordinates plot = PCP(labels=[f"f{i+1}" for i in range(5)]) plot.add(result.F, alpha=0.3) plot.show()
See: scripts/many_objective_example.py for complete example
When: Solving domain-specific optimization problem
Steps:
ElementwiseProblem class__init__ with problem dimensions and bounds_evaluate method for objectives (and constraints)Unconstrained example:
pythonfrom pymoo.core.problem import ElementwiseProblem import numpy as np class MyProblem(ElementwiseProblem): def __init__(self): super().__init__( n_var=2, # Number of variables n_obj=2, # Number of objectives xl=np.array([0, 0]), # Lower bounds xu=np.array([5, 5]) # Upper bounds ) def _evaluate(self, x, out, *args, **kwargs): # Define objectives f1 = x[0]**2 + x[1]**2 f2 = (x[0]-1)**2 + (x[1]-1)**2 out["F"] = [f1, f2]
Constrained example:
pythonclass ConstrainedProblem(ElementwiseProblem): def __init__(self): super().__init__( n_var=2, n_obj=2, n_ieq_constr=2, # Inequality constraints n_eq_constr=1, # Equality constraints xl=np.array([0, 0]), xu=np.array([5, 5]) ) def _evaluate(self, x, out, *args, **kwargs): # Objectives out["F"] = [f1, f2] # Inequality constraints (g <= 0) out["G"] = [g1, g2] # Equality constraints (h = 0) out["H"] = [h1]
Constraint formulation rules:
g(x) <= 0 (feasible when ≤ 0)h(x) = 0 (feasible when = 0)g(x) >= b to -(g(x) - b) <= 0See: scripts/custom_problem_example.py for complete examples
When: Problem has feasibility constraints
Approach options:
1. Feasibility First (Default - Recommended)
pythonfrom pymoo.algorithms.moo.nsga2 import NSGA2 # Works automatically with constrained problems algorithm = NSGA2(pop_size=100) result = minimize(problem, algorithm, termination) # Check feasibility feasible = result.CV[:, 0] == 0 # CV = constraint violation print(f"Feasible solutions: {np.sum(feasible)}")
2. Penalty Method
pythonfrom pymoo.constraints.as_penalty import ConstraintsAsPenalty # Wrap problem to convert constraints to penalties problem_penalized = ConstraintsAsPenalty(problem, penalty=1e6)
3. Constraint as Objective
pythonfrom pymoo.constraints.as_obj import ConstraintsAsObjective # Treat constraint violation as additional objective problem_with_cv = ConstraintsAsObjective(problem)
4. Specialized Algorithms
pythonfrom pymoo.algorithms.soo.nonconvex.sres import SRES # SRES has built-in constraint handling algorithm = SRES()
See: references/constraints_mcdm.md for comprehensive constraint handling guide
When: Have Pareto front, need to select preferred solution(s)
Steps:
Example using Pseudo-Weights:
pythonfrom pymoo.mcdm.pseudo_weights import PseudoWeights import numpy as np # After obtaining result from multi-objective optimization # Normalize objectives F_norm = (result.F - result.F.min(axis=0)) / (result.F.max(axis=0) - result.F.min(axis=0)) # Define preferences (must sum to 1) weights = np.array([0.3, 0.7]) # 30% f1, 70% f2 # Apply decision making dm = PseudoWeights(weights) selected_idx = dm.do(F_norm) # Get selected solution best_solution = result.X[selected_idx] best_objectives = result.F[selected_idx] print(f"Selected solution: {best_solution}") print(f"Objective values: {best_objectives}")
Other MCDM methods:
See:
scripts/decision_making_example.py for complete examplereferences/constraints_mcdm.md for detailed MCDM methodsChoose visualization based on number of objectives:
2 objectives: Scatter Plot
pythonfrom pymoo.visualization.scatter import Scatter plot = Scatter(title="Bi-objective Results") plot.add(result.F, color="blue", alpha=0.7) plot.show()
3 objectives: 3D Scatter
pythonplot = Scatter(title="Tri-objective Results") plot.add(result.F) # Automatically renders in 3D plot.show()
4+ objectives: Parallel Coordinate Plot
pythonfrom pymoo.visualization.pcp import PCP plot = PCP( labels=[f"f{i+1}" for i in range(n_obj)], normalize_each_axis=True ) plot.add(result.F, alpha=0.3) plot.show()
Solution comparison: Petal Diagram
pythonfrom pymoo.visualization.petal import Petal plot = Petal( bounds=[result.F.min(axis=0), result.F.max(axis=0)], labels=["Cost", "Weight", "Efficiency"] ) plot.add(solution_A, label="Design A") plot.add(solution_B, label="Design B") plot.show()
See: references/visualization.md for all visualization types and usage
When: Each _evaluate call is expensive (simulations, ML models, external solvers)
Approach: Pass an elementwise_runner to ElementwiseProblem using StarmapParallelization or JoblibParallelization.
Example (thread pool):
pythonfrom multiprocessing.pool import ThreadPool from pymoo.algorithms.soo.nonconvex.ga import GA from pymoo.core.problem import ElementwiseProblem from pymoo.optimize import minimize from pymoo.parallelization.starmap import StarmapParallelization class MyProblem(ElementwiseProblem): def __init__(self, elementwise_runner=None, **kwargs): super().__init__( n_var=10, n_obj=1, xl=-5, xu=5, elementwise_runner=elementwise_runner, **kwargs, ) def _evaluate(self, x, out, *args, **kwargs): out["F"] = (x ** 2).sum() # Replace with expensive evaluation pool = ThreadPool(4) runner = StarmapParallelization(pool.starmap) problem = MyProblem(elementwise_runner=runner) result = minimize(problem, GA(), ("n_gen", 50), seed=1) pool.close()
See: references/parallelization.md for process pools, joblib, and pickling notes
When: Decision variables include continuous, integer, binary, and/or categorical types
Approach: Define a vars dict with typed variables; use MixedVariableGA (SOO) or add MOO survival.
Example:
pythonfrom pymoo.core.problem import ElementwiseProblem from pymoo.core.variable import Real, Integer, Choice, Binary from pymoo.core.mixed import MixedVariableGA from pymoo.optimize import minimize class MixedProblem(ElementwiseProblem): def __init__(self, **kwargs): vars = { "b": Binary(), "x": Choice(options=["nothing", "multiply"]), "y": Integer(bounds=(0, 2)), "z": Real(bounds=(0, 5)), } super().__init__(vars=vars, n_obj=1, **kwargs) def _evaluate(self, X, out, *args, **kwargs): b, x, z, y = X["b"], X["x"], X["z"], X["y"] f = z + y if b: f = 100 * f if x == "multiply": f = 10 * f out["F"] = f algorithm = MixedVariableGA(pop_size=20) result = minimize(MixedProblem(), algorithm, ("n_evals", 1000), seed=1)
For multi-objective mixed-variable problems, use MixedVariableGA(pop_size=20, survival=RankAndCrowdingSurvival()). For single-objective mixed search, pymoo also wraps Optuna via pymoo.algorithms.soo.nonconvex.optuna.Optuna.
See: references/algorithms.md for MixedVariableGA and Optuna details
| Algorithm | Best For | Key Features | |-----------|----------|--------------| | GA | General-purpose | Flexible, customizable operators | | DE | Continuous optimization | Good global search | | PSO | Smooth landscapes | Fast convergence | | CMA-ES | Difficult/noisy problems | Self-adapting |
| Algorithm | Best For | Key Features | |-----------|----------|--------------| | NSGA-II | Standard benchmark | Fast, reliable, well-tested | | SPEA2 | Archive-based MOO | Strength-based fitness, external archive | | R-NSGA-II | Preference regions | Reference point guidance | | MOEA/D | Decomposable problems | Scalarization approach |
| Algorithm | Best For | Key Features | |-----------|----------|--------------| | NSGA-III | 4-15 objectives | Reference direction-based | | RVEA | Adaptive search | Reference vector evolution | | AGE-MOEA | Complex landscapes | Adaptive geometry |
| Approach | Algorithm | When to Use | |----------|-----------|-------------| | Feasibility-first | Any algorithm | Large feasible region | | Specialized | SRES, ISRES | Heavy constraints | | Penalty | GA + penalty | Algorithm compatibility |
See: references/algorithms.md for comprehensive algorithm reference
pythonfrom pymoo.problems import get_problem # Single-objective problem = get_problem("rastrigin", n_var=10) problem = get_problem("rosenbrock", n_var=10) # Multi-objective problem = get_problem("zdt1") # Convex front problem = get_problem("zdt2") # Non-convex front problem = get_problem("zdt3") # Disconnected front # Many-objective problem = get_problem("dtlz2", n_obj=5, n_var=12) problem = get_problem("dtlz7", n_obj=4)
See: references/problems.md for complete test problem reference
pythonfrom pymoo.algorithms.soo.nonconvex.ga import GA from pymoo.operators.crossover.sbx import SBX from pymoo.operators.mutation.pm import PM algorithm = GA( pop_size=100, crossover=SBX(prob=0.9, eta=15), mutation=PM(eta=20), eliminate_duplicates=True )
Continuous variables:
Binary variables:
Permutations (TSP, scheduling):
See: references/operators.md for comprehensive operator reference
Problem: Algorithm not converging
Problem: Poor Pareto front distribution
Problem: Few feasible solutions
Problem: High computational cost
elementwise_runner (see Workflow 8)save_history=TrueThis skill includes comprehensive reference documentation and executable examples:
Detailed documentation for in-depth understanding:
Search patterns for references:
grep -r "NSGA-II\|NSGA-III\|MOEA/D" references/grep -r "Feasibility First\|Penalty\|Repair" references/grep -r "Scatter\|PCP\|Petal" references/Executable examples demonstrating common workflows:
Run examples:
bashpython3 scripts/single_objective_example.py python3 scripts/multi_objective_example.py python3 scripts/many_objective_example.py python3 scripts/custom_problem_example.py python3 scripts/decision_making_example.py
Common patterns:
ElementwiseProblem for custom problems (or FunctionalProblem for function-based definitions)vars dict with typed variables for mixed-variable problemsg(x) <= 0 and h(x) = 0('n_gen', N) or get_termination("f_tol", tol=0.001)| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 19,820 | 16,723 | -16% | 1 | 1 | 0% | 2,899 | 7,269 | +151% | 0 | 0 | — |
case-02 | fail→pass | 17,081 | 13,437 | -21% | 1 | 1 | 0% | 3,553 | 8,140 | +129% | 0 | 0 | — |
case-03 | pass→pass | 14,389 | 16,255 | +13% | 1 | 1 | 0% | 2,853 | 8,714 | +205% | 0 | 0 | — |
case-04 | pass→pass | 14,797 | 14,265 | -4% | 1 | 1 | 0% | 2,565 | 8,279 | +223% | 0 | 0 | — |
case-05 | pass→pass | 12,792 | 8,892 | -30% | 1 | 1 | 0% | 2,722 | 7,353 | +170% | 0 | 0 | — |
case-06 | pass→pass | 9,689 | 7,652 | -21% | 1 | 1 | 0% | 1,900 | 6,420 | +238% | 0 | 0 | — |
case-07 | pass→pass | 10,925 | 10,468 | -4% | 1 | 1 | 0% | 1,734 | 7,074 | +308% | 0 | 0 | — |
case-08 | pass→pass | 6,745 | 5,453 | -19% | 1 | 1 | 0% | 1,072 | 6,222 | +480% | 0 | 0 | — |
case-09 | pass→pass | 20,112 | 14,026 | -30% | 1 | 1 | 0% | 4,046 | 8,117 | +101% | 0 | 0 | — |
case-10 | pass→pass | 12,786 | 9,353 | -27% | 1 | 1 | 0% | 1,864 | 6,850 | +267% | 0 | 0 | — |
case-11 | pass→pass | 10,365 | 4,793 | -54% | 1 | 1 | 0% | 1,904 | 6,393 | +236% | 0 | 0 | — |
case-12 | pass→pass | 3,559 | 3,081 | -13% | 1 | 1 | 0% | 653 | 5,976 | +815% | 0 | 0 | — |
case-13 | pass→pass | 6,428 | 4,967 | -23% | 1 | 1 | 0% | 1,117 | 6,342 | +468% | 0 | 0 | — |
case-14 | fail→pass | 21,593 | 14,654 | -32% | 1 | 1 | 0% | 3,446 | 7,779 | +126% | 0 | 0 | — |
case-15 | pass→pass | 11,327 | 6,270 | -45% | 1 | 1 | 0% | 1,672 | 6,416 | +284% | 0 | 0 | — |
case-16 | pass→pass | 7,788 | 4,002 | -49% | 1 | 1 | 0% | 1,483 | 6,134 | +314% | 0 | 0 | — |
case-17 | pass→pass | 5,134 | 4,805 | -6% | 1 | 1 | 0% | 991 | 6,117 | +517% | 0 | 0 | — |
case-18 | pass→pass | 7,034 | 5,213 | -26% | 1 | 1 | 0% | 969 | 6,428 | +563% | 0 | 0 | — |
case-19 | pass→pass | 7,137 | 4,438 | -38% | 1 | 1 | 0% | 1,224 | 6,329 | +417% | 0 | 0 | — |
case-20 | pass→pass | 8,218 | 7,445 | -9% | 1 | 1 | 0% | 1,323 | 6,555 | +395% | 0 | 0 | — |
case-21 | pass→pass | 6,439 | 5,007 | -22% | 1 | 1 | 0% | 1,308 | 6,320 | +383% | 0 | 0 | — |
case-22 | pass→pass | 7,096 | 5,205 | -27% | 1 | 1 | 0% | 1,034 | 6,163 | +496% | 0 | 0 | — |
case-23 | fail→pass | 17,013 | 5,066 | -70% | 1 | 1 | 0% | 2,581 | 6,259 | +143% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +17 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.