Library / SDK
PythonOT/POT avatar
PythonOT/POT

POT: a solver collection for optimal transport in Python

POT : Python Optimal Transport

2,844 stars563 forksPythonMIT

At a glance

What is it?
POT packages exact and regularized optimal transport solvers, Gromov-Wasserstein variants, barycenters and backend adapters behind a single Python API. It is a research-grade numerical library, and the choice between its solvers is the real work.
Who is it for?
Adopt POT when you need a named optimal transport formulation (entropic OT, Gromov-Wasserstein, unbalanced or partial OT, barycenters) and you want it differentiable in PyTorch, JAX, TensorFlow, CuPy or NumPy. Do not adopt it as a drop-in Wasserstein distance for two 1D arrays, and do not expect a single solver to fit every problem size: the README itself flags the LP-based non-regularized barycenter as small scale only.
Can I use it commercially?
Yes. MIT 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 1 day 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 September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap POT fills between a distance formula and a working solver

The Wasserstein distance has a clean definition and a bad default implementation. Written as a linear program over a cost matrix, it scales poorly and is not differentiable in the parameters you usually care about. POT exists to supply the alternatives: the README describes the library as providing "several solvers for optimization problems related to Optimal Transport for signal, image processing and machine learning". The audience is narrower than that sentence suggests. It is researchers and engineers who already know which transport formulation they want and need a tested implementation of it, plus the regularized or stochastic variants that make it tractable. If you only need the distance between two one-dimensional samples, the exact 1D solver here is convenient, but so is a one-line call elsewhere. POT earns its place when the problem is a coupling, a barycenter, or a structured comparison between graphs.

Exact, entropic, stochastic: three routes through the same cost matrix

The README lists an OT Network Simplex solver for the linear program, conditional gradient and generalized conditional gradient methods for regularized OT, and an entropic solver built on Sinkhorn-Knopp with a stabilized version, a lazy CPU/GPU solver attributed to geomloss, greedy Sinkhorn and Screening Sinkhorn. These are not interchangeable. The simplex solver targets the exact linear program; the entropic family replaces the hard constraint with a regularized objective, which is what makes gradients flow and what makes the iteration cheap per step. Above that sit large-scale options: a stochastic solver and differentiable losses for the semi-dual and dual formulations. The practical consequence is that solver choice is a first-class decision in POT, not a detail. Entropic methods introduce a regularization strength that shapes both the solution and the numerical behaviour, and the documentation presents the algorithms rather than a default recipe for picking that value.

Gromov-Wasserstein and the structured-data solvers

The part of POT that has no simple substitute is the Gromov-Wasserstein family. GW compares distributions by their internal distance structure rather than by a shared ground metric, which is what you want when the two objects live in different spaces. The README lists exact and regularized GW distances, GW barycenters, Fused Gromov-Wasserstein and FGW barycenters, a sampled GW solver for large problems with arbitrary loss functions, semi-relaxed (F)GW divergences with matching barycenter solvers, and quantized (F)GW distances. Graph Dictionary Learning solvers provide gradients for the GW computation. This is a dense surface area, and it reflects an active research field rather than a settled API. Expect to read the linked examples for each variant, because the names alone do not tell you which formulation tolerates unmatched mass or missing correspondences.

Backends: one solver, five array libraries

POT advertises backends for PyTorch, JAX, TensorFlow, NumPy and CuPy, described in the README as a way to use POT with arrays from any of them. The mechanism is a backend abstraction: solver code is written against array operations, and the backend determines which library executes them. The payoff is that a Sinkhorn iteration can run on GPU arrays or inside an autodiff graph without a separate implementation per framework. The cost is that not every solver is equally exercised on every backend, and the README points to a quickstart section on solving OT with multiple backends rather than claiming uniform coverage. Treat backend support as something to confirm per solver for your version, especially for the newer Gromov-Wasserstein variants and the lazy geomloss-derived solver.

Installing POT and the shape of the API

The README carries PyPI and conda-forge badges, so the two distribution channels are the intended install paths. The package name is pot on both, while the import name is ot. A pip install lands the released version; conda-forge is the alternative for environments already managed by conda. The documentation site is PythonOT.github.io, and the README links a quickstart page plus one worked example per solver family, including plot_OT_1D, plot_optim_OTreg, plot_gromov, plot_fgw, plot_barycenter_lp_vs_entropic and plot_stochastic. Those examples are the effective API reference: each one names the function it calls and the arguments it passes. There is no configuration file and no service to run. The library is imported into an existing Python process, and the version you pin is the version whose solver behaviour you get.

Where POT is the wrong tool

Two limits are stated plainly in the material. The non-regularized Wasserstein barycenter solved with a linear program is marked "only small scale" in the README, which is the honest way of saying that exact barycenters do not survive a few thousand points. The entropic alternatives exist precisely because the exact route does not scale, and they trade exactness for a regularized objective. The second limit is conceptual: POT is a numerical library, not a pipeline. It does not choose a cost function, normalize your features, or tell you whether transport is the right comparison for your data. If your two distributions are one-dimensional samples and you want a number, the exact 1D solver is fine, but so is scipy.stats.wasserstein_distance, and reaching for POT adds a dependency for no gain. The library also assumes you can afford to read the examples: the breadth of formulations means the function name is often the only hint about which assumptions a solver makes.

How POT differs from GeomLoss and from SciPy

GeomLoss is the closest point of comparison, and the README makes the relationship concrete rather than competitive: POT includes a "lazy CPU/GPU solver from geomloss" among its entropic options. GeomLoss is built around kernelized entropic OT and sample-based losses, which suits large point clouds and differentiable training objectives where you rarely want an explicit coupling matrix. POT is broader and more explicit: it exposes the coupling, ships exact linear-program solvers, and covers discrete structured problems such as Gromov-Wasserstein and graph dictionary learning that a sample-based loss library does not target. SciPy sits at the opposite end. scipy.stats.wasserstein_distance computes the 1D Wasserstein distance and nothing else. If your problem is a barycenter, a coupling, an unbalanced formulation, or a comparison between graphs, SciPy has no answer and POT does. If your problem is a scalar distance between two 1D arrays, POT is a heavier answer to a question SciPy already answers.

Maintenance, releases and the MIT licence

POT is MIT licensed, which permits commercial use and modification provided the copyright notice and permission notice are retained. That is a permissive arrangement, and it is the licence under which the source is published on GitHub. This is not legal advice; read the LICENSE file before relying on it. On maintenance, the repository is not archived and the release history shows 0.9.7 in July 2026, a 0.9.7.post1 shortly after, and 0.9.6.post1 in September 2025. The post-release pattern is worth noting: a post1 usually means packaging or build fixes rather than new solvers, so the upgrade cost between a release and its post variant is low. Upgrading across minor versions is the real cost, because solver behaviour in a numerical library is part of its interface. Pin the version in your environment and re-run the example scripts that match your solver family after any bump.

Editorial conclusion

Adopt POT when you need a named optimal transport formulation (entropic OT, Gromov-Wasserstein, unbalanced or partial OT, barycenters) and you want it differentiable in PyTorch, JAX, TensorFlow, CuPy or NumPy. Do not adopt it as a drop-in Wasserstein distance for two 1D arrays, and do not expect a single solver to fit every problem size: the README itself flags the LP-based non-regularized barycenter as small scale only. Before committing, verify on your own data which solver stays stable, since entropic solvers need a regularization parameter and the documentation does not pick one for you.

Official sources

  1. License: MIT
  2. Project website
  3. PythonOT/POT on GitHub
  4. README
  5. Releases
Community notes

Community notes