Skip to content
Draft
1 change: 1 addition & 0 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,4 @@ keywords:
- gromov-wasserstein
license: MIT
version: 0.9.7
date-released: 2026-07-10
24 changes: 16 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,25 @@ using the following references from the current version and from our [JMLR
paper](https://jmlr.org/papers/v22/20-451.html):

```
Flamary R., Vincent-Cuaz C., Courty N., Gramfort A., Kachaiev O., Quang Tran H., David L., Bonet C., Cassereau N., Gnassounou T., Tanguy E., Delon J., Collas A., Mazelet S., Chapel L., Kerdoncuff T., Yu X., Feickert M., Krzakala P., Liu T., Fernandes Montesuma E. POT Python Optimal Transport (version 0.9.5). URL: https://github.com/PythonOT/POT
Flamary R., Vincent-Cuaz C., Courty N., Gramfort A., Kachaiev O., Quang Tran H., David L., Bonet C., Cassereau N., Gnassounou T., Tanguy E., Delon J., Collas A., Mazelet S., Chapel L., Kerdoncuff T., Yu X., Feickert M., Krzakala P., Liu T., Fernandes Montesuma E., Neike N., Genest B., Coeurjolly D., Germain T., O'Shea S., Corneli M., Genans F. (2026). POT Python Optimal Transport (version 0.9.7). DOI: 10.5281/zenodo.17161062 URL: https://github.com/PythonOT/POT

Rémi Flamary, Nicolas Courty, Alexandre Gramfort, Mokhtar Z. Alaya, Aurélie Boisbunon, Stanislas Chambon, Laetitia Chapel, Adrien Corenflos, Kilian Fatras, Nemo Fournier, Léo Gautheron, Nathalie T.H. Gayraud, Hicham Janati, Alain Rakotomamonjy, Ievgen Redko, Antoine Rolet, Antony Schutz, Vivien Seguy, Danica J. Sutherland, Romain Tavenard, Alexander Tong, Titouan Vayer, POT Python Optimal Transport library, Journal of Machine Learning Research, 22(78):1−8, 2021. URL: https://pythonot.github.io/
```

In Bibtex format:

```bibtex
@misc{flamary2024pot,
author = {Flamary, R{\'e}mi and Vincent-Cuaz, C{\'e}dric and Courty, Nicolas and Gramfort, Alexandre and Kachaiev, Oleksii and Quang Tran, Huy and David, Laurène and Bonet, Cl{\'e}ment and Cassereau, Nathan and Gnassounou, Th{\'e}o and Tanguy, Eloi and Delon, Julie and Collas, Antoine and Mazelet, Sonia and Chapel, Laetitia and Kerdoncuff, Tanguy and Yu, Xizheng and Feickert, Matthew and Krzakala, Paul and Liu, Tianlin and Fernandes Montesuma, Eduardo},
title = {POT Python Optimal Transport (version 0.9.5)},
url = {https://github.com/PythonOT/POT},
year = {2024}
@software{flamary2026pot,
author = {Flamary, Rémi and Vincent-Cuaz, Cédric and Courty, Nicolas and Gramfort, Alexandre and Kachaiev, Oleksii and Quang Tran, Huy and David, Laurène and Bonet, Clément and Cassereau, Nathan and Gnassounou, Théo and Tanguy, Eloi and Delon, Julie and Collas, Antoine and Mazelet, Sonia and Chapel, Laetitia and Kerdoncuff, Tanguy and Yu, Xizheng and Feickert, Matthew and Krzakala, Paul and Liu, Tianlin and Fernandes Montesuma, Eduardo and Neike, Nathan and Genest, Baptiste and Coeurjolly, David and Germain, Thibaut and O'Shea, Sienna and Corneli, Marco and Genans, Ferdinand},
doi = {10.5281/zenodo.17161062},
month = {7},
title = {POT Python Optimal Transport},
version = {0.9.7},
url = {https://github.com/PythonOT/POT},
year = {2026}
}


@article{flamary2021pot,
author = {R{\'e}mi Flamary and Nicolas Courty and Alexandre Gramfort and Mokhtar Z. Alaya and Aur{\'e}lie Boisbunon and Stanislas Chambon and Laetitia Chapel and Adrien Corenflos and Kilian Fatras and Nemo Fournier and L{\'e}o Gautheron and Nathalie T.H. Gayraud and Hicham Janati and Alain Rakotomamonjy and Ievgen Redko and Antoine Rolet and Antony Schutz and Vivien Seguy and Danica J. Sutherland and Romain Tavenard and Alexander Tong and Titouan Vayer},
title = {POT: Python Optimal Transport},
Expand Down Expand Up @@ -467,8 +471,12 @@ Artificial Intelligence.

\[88] Bouveyron, C. & Corneli, M. (2026). [Scaling optimal transport to high-dimensional Gaussian distributions with application to domain adaptation](https://hal.science/hal-04930868v4/file/Article-OT-HDGauss-v4.pdf). Statistics and Computing 36.2 (2026): 88.

\[89] Tipping, M.E. & Bishop, C.M. (1999). [Probabilistic principal component analysis]. Journal of the Royal Statistical Society Series B: Statistical Methodology 61.3 (1999): 611-622.
\[89] Tipping, M.E. & Bishop, C.M. (1999). [Probabilistic principal component analysis](https://www.cs.columbia.edu/~blei/seminar/2020-representation/readings/TippingBishop1999.pdf). Journal of the Royal Statistical Society Series B: Statistical Methodology 61.3 (1999): 611-622.

\[90] Genans, F., Godichon-Baggioni, A., Vialard, F. X., & Wintenberger, O. (2025). [Decreasing Entropic Regularization Averaged Gradient for Semi-Discrete Optimal Transport](https://proceedings.neurips.cc/paper_files/paper/2025/file/d7efa12e98f5e0dd8b4f48cd60b4e3aa-Paper-Conference.pdf). Advances in Neural Information Processing Systems, 38, 146913-146949.

\[91] Fatras, K., Zine, Y., Majewski, S., Flamary, R., Gribonval, R., & Courty, N. (2021). [Minibatch optimal transport distances; analysis and applications](https://arxiv.org/pdf/2101.01792). arXiv preprint arXiv:2101.01792.
\[91] Fatras, K., Zine, Y., Majewski, S., Flamary, R., Gribonval, R., & Courty, N. (2021). [Minibatch optimal transport distances; analysis and applications](https://arxiv.org/pdf/2101.01792). arXiv preprint arXiv:2101.01792.

\[92] Xie, Y., Wang, X., Wang, R., & Zha, H. (2020, August).
[A fast proximal point method for computing exact wasserstein distance.](https://proceedings.mlr.press/v115/xie20b/xie20b.pdf) In Uncertainty in artificial intelligence (pp. 433-453). PMLR.

43 changes: 38 additions & 5 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,43 @@

## 0.9.7

This new release adds support for sparse cost matrices and a new lazy exact OT solver that re-computes distances on-the-fly from coordinates, reducing memory usage from O(n×m) to O(n+m). Both implementations are backend-agnostic and preserve gradient computation for automatic differentiation.
This release contains several bug fixes and performance improvements, as well as updates to the documentation and examples and tests. We provide below a summary of the main new features and closed issues.


**New exact OT solvers.** This new release adds many new variants and updates for the exact OT solver. First a new lazy exact OT solver that re-computes distances on-the-fly from coordinates, reducing memory usage from O(n×m) to O(n+m) ( available in [`ot.solve_sample`](https://pythonot.github.io/all.html#ot.solve_sample) with `lazy=True)`). Another major feature is the addition of a warmstart feature for the EMD solver, allowing users to provide initial potentials to speed up convergence (with `init_potentials` in [`ot.solve`](https://pythonot.github.io/all.html#ot.solve) and [`ot.solve_sample`](https://pythonot.github.io/all.html#ot.solve_sample)). Finally the release also include a sparse solver and [`ot.solve`](https://pythonot.github.io/all.html#ot.solve) now accept sparse cost matrices and provides an OT plan whose support is included in the support of the cost matrix. All implementations are backend-agnostic and preserve gradient computation for automatic differentiation (but are solved on CPU).

The computational time for different solvers (on a laptop CPU) are shown below:

| n| 100| 500| 1000| 5000|
|--------------------------|:------------------------:|:------------------------:|:------------------------:|:------------------------:|
| Solve | 7.259e-04| 1.501e-02| 1.055e-01| 2.343e+00|
| Solve Warm Start | 6.970e-04| 5.413e-03| 2.291e-02| 6.036e-01|
| Solve Lazy | 1.280e-03| 3.098e-02| 1.421e-01| 3.377e+00|
| Solve Sparse 10% | 3.453e-04| 6.716e-04| 1.535e-03| 3.534e-02|


**BSPOT solver.** A new solver relying on [Binary Space Partitioning (BSP)](https://pythonot.github.io/master/auto_examples/plot_bsp_ot.html) has been added to compute sparse transport plans between discrete measures in loglinear time which allows for very large problems to be solved. The release also includes a new [`ot.unbalanced.uot_1d`](https://pythonot.github.io/master/gen_modules/ot.unbalanced.html#ot.unbalanced.uot_1d) solver with a Frank-Wolfe solver for unbalanced optimal transport in 1D.

**Sliced OT pans** Finally we now have a sliced OT plan solver that can be used to compute sliced transport plans ([min-pivot sliced](https://pythonot.github.io/master/gen_modules/ot.sliced.html#ot.sliced.min_sliced_transport_plan) and [expected sliced](https://pythonot.github.io/master/gen_modules/ot.sliced.html#ot.sliced.expected_sliced_plan)) between two measures.

**OT between dynamical systems.** A novel [Spectral-Grassmann Wasserstein metric for operator representations of dynamical systems](https://pythonot.github.io/master/auto_examples/others/plot_sgot.html) has been implemented in `ot.sgot`.

**Unified API for barycenter solvers in `ot.solve_bary_sample`.** A new free support solver for barycenter solvers has been added in [`ot.solve_bary_sample`](https://pythonot.github.io/master/all.html#ot.solve_bary_sample). You can see [examples of how to use it here](https://pythonot.github.io/master/auto_examples/barycenters/plot_solve_barycenter_variants.html).

**OT between high dimensional Gaussian distributions.** New methods to compute the linear transport map and the related 2-Wasserstein distance between high-dimensional (HD) Gaussian distributions have been added in [`ot.gaussian.bures_wasserstein_mapping_hd`](https://pythonot.github.io/master/gen_modules/ot.gaussian.html#id56) and [`ot.gaussian.bures_wasserstein_distance_hd`](https://pythonot.github.io/master/gen_modules/ot.gaussian.html#ot.gaussian.bures_wasserstein_distance_hd), respectively with empirical versions that estimate the distance from sample.

**Batched solver for exact OT.** The batch implementations have also been improved and you can now solve exact OT problems in parallel on CPU or GPU using the new proximal point solver in functions [`ot.solve_batch`](https://pythonot.github.io/master/gen_modules/ot.batch.html#ot.batch.solve_batch) and [`ot.solve_sample_batch`](https://pythonot.github.io/master/gen_modules/ot.batch.html#ot.batch.solve_sample_batch) when `reg=0` or no provided. A new batch [loss for Fused unbalanced Gromov-Wasserstein](https://pythonot.github.io/master/gen_modules/ot.batch.html#ot.batch.loss_quadratic_batch) is also now available in `ot.batch`.


**New methods in unified API [`ot.solve_sample`](https://pythonot.github.io/all.html#ot.solve_sample).** The unified API function
[`ot.solve_sample`](https://pythonot.github.io/all.html#ot.solve_sample) has also been updated to allows solving of specific problems such as BSP-OT, distance between high-dimensional (HD) Gaussian distributions and sliced and max-sliced distances.


**Data normalization for sliced and [`ot.solve_sample`](https://pythonot.github.io/all.html#ot.solve_sample) solvers.** The release also includes tools for data normalization and scaling which can not be used in sliced Wasserstein distance computations. A simple normalization class [`ot.utils.DataScaler`](https://pythonot.github.io/master/gen_modules/ot.utils.html#id46) has been added and supports all backends for `'standard'`, `'minmax'`, and `'l2'` methods. Finally an optional `scaler` parameter has been added to [`ot.sliced_wasserstein_distance`](https://pythonot.github.io/master/all.html#ot.sliced_wasserstein_distance), [`ot.max_sliced_wasserstein_distance`](https://pythonot.github.io/master/all.html#ot.max_sliced_wasserstein_distance) and [`ot.solve_sample`](https://pythonot.github.io/all.html#ot.solve_sample).


#### New features

- Fix reference number error introduced in PR #767 (PR #819)
- Refactor lazy EMD network simplex storage to avoid dense per-arc cost,
endpoint, flow, and state storage where possible, and return sparse lazy
transport plans instead of materializing dense plans internally (PR #813)
Expand All @@ -28,21 +60,21 @@ This new release adds support for sparse cost matrices and a new lazy exact OT s
- Add optional `scaler` parameter to `sliced_wasserstein_distance` and `max_sliced_wasserstein_distance` (PR #808)
- Add SGD based semi-discrete OT solver in `ot.semidiscrete` and a gallery example. (PR #812)
- Add a numerically stable log-domain solver for entropic partial Wasserstein, selectable via the new `method` parameter of `entropic_partial_wasserstein` (`method='sinkhorn_log'`) or directly through `entropic_partial_wasserstein_logscale` (Issue #723)
- Add cost functions between linear operators following
[A Spectral-Grassmann Wasserstein metric for operator representations of dynamical systems](https://arxiv.org/pdf/2509.24920),
implemented in `ot.sgot` (PR #792)
- Add cost functions between linear operators following [A Spectral-Grassmann Wasserstein metric for operator representations of dynamical systems](https://arxiv.org/pdf/2509.24920), implemented in `ot.sgot` (PR #792, PR #830)
- Add batch FUGW loss to `ot.batch` and fix issues in some default parameters in the batch module (PR #775)
- Wrapper for barycenter solvers with free support `ot.solvers.bary_free_support` (PR #730)
- Build wheels on ubuntu ARM to avoid QEMU emulation (PR #818)
- Add new methods to compute the linear transport map and the related 2-Wasserstein distance betweeen high-dimensional (HD) Gaussian distributions as described in [88], implemented in `ot.gaussian.bures_wasserstein_mapping_hd` and `ot.gaussian.bures_wasserstein_distance_hd`, respectively. Two additional methods estimate the same quantities from the source and destination observed data and are implemented in `ot.gaussian.empirical_bures_wasserstein_mapping_hd` and `ot.gaussian.empirical_bures_wasserstein_distance_hd`, respectively (PR #814)
- Update the geomloss wrapper to the new version and API (PR #826)
- Fix docstrings for `lowrank_gromov_wasserstein_samples` and `lowrank_sinkhorn` (PR #823)
- Reorganize all tests per backend (PR #828)
- Implemented batch proximal point solver for OT problems `ot.batch.proximal_bregman_log_plan_batch` function and updated wrapper functions `ot.batch.solve_batch` and `ot.batch.solve_sample_batch` (PR #832)
- Implement debiased OT solvers in `ot.solve_sample`.


#### Closed issues

- Fix label-aware cost correction in `ot.da` transport classes: the large cost was applied to unlabeled pairs instead of labeled pairs with different labels, so `ys`/`yt` had no effect when all labels were known (PR #833, Issue #664)
- Mitigate NaN regime of `entropic_partial_wasserstein` at small `reg` via a new log-domain solver, reachable with `entropic_partial_wasserstein(..., method='sinkhorn_log')` (Issue #723; the default `method='sinkhorn'` path is unchanged — callers opt into the log-domain variant)
- Fix NumPy 2.x compatibility in Brenier potential bounds (PR #788)
- Fix MSVC Windows build by removing **restrict** keyword (PR #788)
Expand All @@ -60,6 +92,7 @@ This new release adds support for sparse cost matrices and a new lazy exact OT s
- Fix entropic regularization in `gcg`(PR #817, Issue #758)
- Fix documentation build on master with submodules (PR #818)
- Fix failing test for unbalanced solver with generic regularization (PR #824)
- Fix reference number error introduced in PR #767 (PR #819)
- Fix docstrings for `lowrank_gromov_wasserstein_samples` and `lowrank_sinkhorn` (PR #823)
- Update sgot cost function and example (PR #830)

Expand Down
42 changes: 35 additions & 7 deletions examples/backends/plot_ot_batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"""

# Author: Paul Krzakala <paul.krzakala@gmail.com>
# Thibaut Germain <thibaut.germain.pro@gmail.com>
# License: MIT License

# sphinx_gallery_thumbnail_number = 1
Expand Down Expand Up @@ -75,25 +76,52 @@
# This is simple but inefficient for large batches.
#
# Instead, you can use :func:`ot.batch.solve_batch`, which solves all
# problems in parallel.
# problems in parallel. Several methods are available: ["sinkhorn", "log_sinkhorn"]
# which solve regularized OT problems, and ["proximal"] which
# solves regularized and unregularized OT problem using a proximal point scheme.
# By default, the method is set to "auto" which automatically selects the appropriate
# method based on the value of `reg`. If `reg` is None or 0, the proximal point method
# is used. If `reg` is greater than 0, the Sinkhorn algorithm is used.

max_iter = 10000
tol = 1e-4

# Classical OT problem
## Naive approach
results_values_list = []
for i in range(n_problems):
res = ot.solve(M_list[i], max_iter=max_iter, tol=tol)
results_values_list.append(res.value_linear)

reg = 1.0
max_iter = 100
tol = 1e-3
## Batched approach
results_batch = ot.solve_batch(M=M_batch, max_iter=max_iter, tol=tol)
results_values_batch = results_batch.value_linear

# Naive approach
exact_validated = np.allclose(
np.array(results_values_list), results_values_batch, atol=tol * 10
)

# Entropic regularized OT problem
## Naive approach
reg = 1.0
results_values_list = []
for i in range(n_problems):
res = ot.solve(M_list[i], reg=reg, max_iter=max_iter, tol=tol, reg_type="entropy")
results_values_list.append(res.value_linear)

# Batched approach
## Batched approach
results_batch = ot.solve_batch(
M=M_batch, reg=reg, max_iter=max_iter, tol=tol, reg_type="entropy"
)
results_values_batch = results_batch.value_linear

assert np.allclose(np.array(results_values_list), results_values_batch, atol=tol * 10)
entropic_validated = np.allclose(
np.array(results_values_list), results_values_batch, atol=tol * 10
)

print(
f"Exact solve vs proximal batch close: {exact_validated} \nSinkhorn solve vs Sinkhorn solve_batch close: {entropic_validated}"
)

#############################################################################
#
Expand Down
2 changes: 1 addition & 1 deletion ot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
from .utils import dist, unif, tic, toc, toq


__version__ = "0.9.7.dev0"
__version__ = "0.9.7"

__all__ = [
"emd",
Expand Down
3 changes: 3 additions & 0 deletions ot/batch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

# Author: Remi Flamary <remi.flamary@unice.fr>
# Paul Krzakala <paul.krzakala@gmail.com>
# Thibaut Germain <thibaut.germain.pro@gmail.com>
#
# License: MIT License

Expand All @@ -25,6 +26,7 @@
bregman_log_projection_batch,
bregman_projection_batch,
entropy_batch,
proximal_bregman_log_plan_batch,
)

__all__ = [
Expand All @@ -40,4 +42,5 @@
"loss_quadratic_batch",
"loss_quadratic_samples_batch",
"tensor_batch",
"proximal_bregman_log_plan_batch",
]
Loading
Loading