Library / SDK
anyoptimization/pymoo avatar
anyoptimization/pymoo

pymoo compiles part of itself with Cython, and the build needs numpy 2 while the runtime accepts 1.19

NSGA2, NSGA3, R-NSGA3, MOEAD, Genetic Algorithms (GA), Differential Evolution (DE), CMAES, PSO

2,968 stars482 forksPythonApache-2.0

At a glance

What is it?
A multi-objective optimization framework whose published algorithm roster runs from NSGA2 through MOEAD, CMA-ES and PSO. Its hypervolume arithmetic is delegated to a compiled library, its build deliberately targets a newer numpy than its runtime floor, and its Makefile still calls the legacy setup.py install.
Who is it for?
pymoo fits work where the objective is genuinely multi-objective, because the library is built around Pareto fronts and the performance indicators that score them, and it is the one part of that stack this repository delegates to compiled C++ rather than to Python. Three things to check before you build against it.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 90 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 4, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Some modules are compiled, and there is a one line command to find out

The installation section says that some modules are also available compiled, for speedup, and then tells the reader how to check whether the compilation worked:

bash
python -c "from pymoo.functions import is_compiled;print('Compiled Extensions: ', is_compiled())"

The warning attached to that command matters more than the command. The README says to be sure not to already be in the local pymoo directory when executing it, because otherwise the version installed in site-packages is not the one that will be used. A source checkout sitting in the working directory shadows the installed package, so the check can report on the wrong copy.

The location of the compiled code is fixed by the build script, which cythonizes a single glob, `pymoo/functions/compiled/*.pyx`, with `force=True`, so the sources are regenerated on every build rather than only when they change. The include directory handed to the compiler is numpy's own, obtained through `numpy.get_include()`, which means the extension is compiled against numpy's C headers rather than against a Python-level interface.

Note that the verification command imports from `pymoo.functions` and the compiled glob lives under `pymoo/functions/compiled/`. The check and the build target the same subtree, so what you are testing is exactly what the build script produces.

The build compiles against numpy 2 and the runtime accepts numpy 1.19

The build requirements and the runtime requirements disagree on purpose, and the file explains why in a comment rather than leaving it to be discovered.

At runtime the floor is `numpy>=1.19.3`. At build time the requirement is `numpy>=2.0.0`, alongside `setuptools>=77` and `Cython>=0.29`.

The stated reason is the C ABI. Building against numpy 2 produces a single wheel that still loads on a runtime of numpy 1.19 or later, because that ABI is backward compatible. The failure being avoided is named as well: an unpinned build numpy could compile against 2.x while a 1.x runtime silently falls back to slow pure Python.

That last clause is the operationally important part. The failure mode is not an import error and not a failed install, it is a working installation that is quietly running interpreted code instead of the compiled extensions, which is exactly the case the verification command in the previous section exists to catch. The two requirements together are therefore a design decision with a test attached to it.

The rest of the build configuration is small. The package layout is flat, with discovery rooted at the repository and including `pymoo*`, and the version is read from an attribute, `pymoo.version.__version__`, listed as dynamic rather than written into the metadata.

moocore does the indicator arithmetic, and a deprecation helper is a runtime dependency

The dependency list is short and one entry does more work than its name suggests. `moocore>=0.3.1` is the compiled core for multi-objective computations, which is where the hypervolume and indicator calculations that score a Pareto front are actually performed. That is the same performance motivation as the Cython extensions, reached through a dependency instead of through a local build.

The rest of the list is the scientific stack a solver needs: `numpy>=1.19.3` and `scipy>=1.1` for numerics, `autograd>=1.4` for gradients, which is why the examples directory has a `gradient.py`, `cma>=3.4.0` for CMA-ES, and `matplotlib>=3` for plotting, which is what the usage example's `Scatter` object draws with.

Two entries are worth naming because they are not what a solver needs. `alive_progress>=3.0` is a progress bar, and it is what the `verbose=True` argument in the usage example renders. `Deprecated>=1.2` is a package whose purpose is to emit deprecation warnings, and it is a required runtime dependency rather than a development tool, so the warning machinery ships to every install.

The algorithm roster in the repository description is the other half of what this library is: NSGA2, NSGA3, R-NSGA3, MOEAD, genetic algorithms, differential evolution, CMA-ES and particle swarm optimization.

A problem is named by string, termination is a tuple, and the example plots the true front too

The usage example is the whole API in nine statements. A problem comes from a string through `get_problem("zdt1")`, the algorithm is constructed with a population size, and the run is terminated by a tuple rather than a number:

python
from pymoo.algorithms.moo.nsga2 import NSGA2
from pymoo.problems import get_problem
from pymoo.optimize import minimize
from pymoo.visualization.scatter import Scatter

problem = get_problem("zdt1")

algorithm = NSGA2(pop_size=100)

res = minimize(problem,
               algorithm,
               ('n_gen', 200),
               seed=1,
               verbose=True)

Three details are decisions rather than syntax. Passing `seed=1` makes the run reproducible, which matters for a stochastic method. Passing `verbose=True` turns on the progress output. And the termination being a tuple, `('n_gen', 200)`, means other criteria are expressible in the same position rather than needing a different call.

The last two statements of the example are the most informative. The plot adds `problem.pareto_front()` as a black line and then adds `res.F` in red, so the figure shows the algorithm's result against the true front of the benchmark problem. That means the library can compute the exact front for these problems, which is a benchmarking capability and not just a solver.

The examples directory is organised the same way, into subdirectories for algorithms, case studies, constraints, experimental work, matlab, misc, non-dominated sorting, problems, termination and visualization, plus standalone files for gradients, indicators, progress, repair and one named `nds.py`.

The citation is a 2020 paper and the Makefile still calls setup.py install

The README asks research users to cite a publication by J. Blank and K. Deb, titled pymoo: Multi-Objective Optimization in Python, published in IEEE Access, volume 8, pages 89497 to 89509, in 2020, with a DOI, and a BibTex block is provided underneath it. That block's `number` field is left empty.

The paper describes a much earlier version than the one you would install. The recent release line is 0.6.1.5 on 2025-05-26, 0.6.1.6 on 2025-11-25 and 0.6.2 on 2026-06-28, so the citation points at a 2020 release of a library currently at 0.6.2. That is normal for a paper that predates the current architecture, and worth knowing if you are citing the software rather than the method.

The version scheme also changes shape across those three tags. Two of them carry a fourth component, so 0.6.1.5 and 0.6.1.6 are patch releases on a three part line, and the third is an ordinary three component 0.6.2. A requirement written as `pymoo>=0.6.1` would admit a patch release that a requirement written as `pymoo==0.6.1.*` would not, which is the practical consequence of mixing the two.

The Makefile is where the age shows. Its targets are clean, which removes build, dist and the egg-info directory; clean-ext, which removes the generated C, shared object, C++ and HTML files from the compiled directory; compile, which builds extensions in place; dist, which builds an sdist; and install, which calls `python setup.py install`. That last one is the legacy install path rather than a wheel build, and there is no wheel target and no test target in the file even though pytest.ini is in the repository.

Support is a personal mailbox, and three root files are not linked from anywhere

The Contact section invites readers to email the maintainer directly with questions, and gives a personal address at Outlook alongside an academic affiliation: Michigan State University, Computational Optimization and Innovation Laboratory, East Lansing, Michigan. The packaging metadata lists the same person and the same address as the sole author.

There is no issue tracker, discussion board or chat link anywhere in the README. Bug reports, however they arrive, therefore start in a mailbox rather than in a searchable queue, which is the opposite of the pattern most projects of this size use.

The repository root is worth reading as well, because several entries are unmentioned. A file named `.gitconfig` sits at the root, which is not one of the standard locations Git reads configuration from and is not explained in the README. A directory named `.pyclawd/` is there with no description of what it contains. And `IMPROVEMENTS.md` exists as a file that nothing in the README links to.

Alongside those, the conventional files are present: `CONTRIBUTING.md` and `CODE_OF_CONDUCT.md` for process, `MANIFEST.in` for the packaging manifest, `mypy.ini` and `pytest.ini` for typing and tests, a `.claude/` directory for automated tooling, and a `docs/` directory for the documentation site the README links throughout.

Docstrings are mid-migration and the docs build renders both conventions

The packaging configuration carries a note about docstrings that explains a choice visible to anyone reading the library. The convention being migrated to is the Google style, with types living in annotations rather than duplicated inside the docstrings, and the migration is described as proceeding module by module from the numpy style. The comment also records that the documentation build renders both conventions, through the Sphinx extension for Napoleon.

That is a small thing with two consequences. Anyone calling `help()` on a function sees a mixture of formats depending on which module it came from, and anyone parsing docstrings for types has to handle both. Neither is a defect; both are the visible cost of an incremental migration, and the file says so rather than leaving it to be discovered.

Installation, for completeness, is three commands. The README asks for a Python 3 environment first and recommends miniconda3 or anaconda3, then gives the PyPI route as `pip install -U pymoo`, and the developer route as a clone of the repository followed by `pip install .` from inside the checkout. The clone command in the README is written without a `.git` suffix, which is the more common way to write it and worth matching to whatever your tooling expects.

Editorial conclusion

pymoo fits work where the objective is genuinely multi-objective, because the library is built around Pareto fronts and the performance indicators that score them, and it is the one part of that stack this repository delegates to compiled C++ rather than to Python. Three things to check before you build against it. Whether the compiled extensions are actually loaded, since the library ships pure Python equivalents and falls back silently, which is why the README provides a one line check and warns you not to run it from inside the source directory. Which numpy you have, since the build compiles against numpy 2 while the runtime accepts 1.19, and a mismatch shows up as slowness rather than as an error. And where to send a question, since the README routes support to the maintainer's personal mailbox rather than to an issue tracker.

Frequently asked questions

what is pymoo

pymoo is a Python framework for multi-objective optimization. Its published algorithm roster covers NSGA2, NSGA3, R-NSGA3, MOEAD, genetic algorithms, differential evolution, CMA-ES and PSO, and it adds visualization and decision making around them. Some modules ship as compiled Cython extensions, and the hypervolume and indicator work is delegated to the moocore library.

how to install pymoo

The README asks for a Python 3 environment, recommending miniconda3 or anaconda3, then gives `pip install -U pymoo` for the official release from PyPI. For the developer version it gives a clone of the repository followed by `pip install .`. Python 3.10 or newer is required, and some modules are compiled for speedup.

How does pymoo compare to scipy, Optuna or DEAP?

The repository does not make that comparison. What it states is its own scope: multi-objective algorithms from the NSGA family through MOEAD, CMA-ES and PSO, a dependency list containing scipy, numpy, autograd, cma and moocore, and Cython extensions under pymoo/functions/compiled. Any claim about the others would have to come from their own documentation.

Does pymoo ship compiled extensions, and how do I check they loaded?

Some modules are available compiled for speedup. The build script cythonizes `pymoo/functions/compiled/*.pyx` with force enabled and passes numpy's include directory to the compiler. The README gives the check `python -c "from pymoo.functions import is_compiled;print('Compiled Extensions: ', is_compiled())"` and warns not to run it from inside the local pymoo directory, where the source checkout would shadow the installed package.

Official sources

  1. anyoptimization/pymoo on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/anyoptimization-pymoo.svg)](https://hysenlabs.com/projects/anyoptimization-pymoo)