# \[ANN\] OptimalTransport.jl - Optimal transport algorithms for Julia

**URL:** <https://discourse.julialang.org/t/ann-optimaltransport-jl-optimal-transport-algorithms-for-julia/39447>\
**Category:** Package Announcements\
**Created:** [May 14, 2020, 6:30am UTC](https://discourse.julialang.org/t/ann-optimaltransport-jl-optimal-transport-algorithms-for-julia/39447 "2020-05-14T06:30:07Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![zsteve](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zsteve/32/14841_2.png) [@zsteve](https://discourse.julialang.org/u/zsteve)\
**Post date:** [May 14, 2020, 6:30am UTC](https://discourse.julialang.org/t/ann-optimaltransport-jl-optimal-transport-algorithms-for-julia/39447/1 "2020-05-14T06:30:08Z")

</div>

Hi all,

I’m pleased to announce OptimalTransport.jl, a Julia package (currently still a work-in-progress) offering various algorithms for computational optimal transport, such as the celebrated Sinkhorn scaling algorithm for entropically regularised optimal transport.

> **[GitHub - zsteve/OptimalTransport.jl: Optimal transport algorithms for Julia](https://github.com/zsteve/OptimalTransport.jl)**
>
> Optimal transport algorithms for Julia

Many algorithms are implemented natively in Julia, whilst other functionality is currently offered as a wrapper to the excellent **POT (Python OT) library [1]**. We will be progressively adding more Julia-implemented algorithms in the future.

Any feedback or suggestions are welcome! 🙂

## Check out the documentation here:

[http://zsteve.phatcode.net/OptimalTransportDocs](http://zsteve.phatcode.net/OptimalTransportDocs)

## Example

```julia
using OptimalTransport
using Seaborn

μ_spt = ν_spt = LinRange(-2, 2, 100)
C = pairwise(Euclidean(), μ_spt', ν_spt').^2
μ = exp.((-(μ_spt).^2)/0.5^2)
μ /= sum(μ)
ν = ν_spt.^2 .*exp.((-(ν_spt).^2)/0.5^2)
ν /= sum(ν)
γ = OptimalTransport.sinkhorn_stabilized(μ, ν, C, 1e-4, max_iter = 5000)
using Random, Distributions

F = DiscreteNonParametric(1:prod(size(γ)), reshape(γ, prod(size(γ))))
t = rand(F, 5*10^3)
μ_idx = t .% size(γ, 1)
ν_idx = t .÷ size(γ, 2)

Seaborn.figure()
Seaborn.jointplot(x = [μ_spt[i] for i in μ_idx], y = [ν_spt[i] for i in ν_idx], kind = "kde")
Seaborn.gcf()
Seaborn.savefig("example.png")

```

 ![example](https://global.discourse-cdn.com/julialang/original/3X/3/4/34da3c01c7ad2e2eb07b5626ebd29fc1d53960f6.png)

## Links

[1] POT Python Optimal Transport library, Flamary, Remi and Courty, Nicolas

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [May 14, 2020, 8:48am UTC](https://discourse.julialang.org/t/ann-optimaltransport-jl-optimal-transport-algorithms-for-julia/39447/2 "2020-05-14T08:48:02Z")

</div>

Nice 🙂  
I have some [optimal-transport related algorithms](https://baggepinnen.github.io/SpectralDistances.jl/latest/distances/#Details-1) like finding [barycenters](https://baggepinnen.github.io/SpectralDistances.jl/latest/interpolations/#Barycenters-1) and [barycentric coordinates](https://baggepinnen.github.io/SpectralDistances.jl/latest/interpolations/#SpectralDistances.barycentric_coordinates-Union%7BTuple%7BT%7D,%20Tuple%7BAny,Any,Any,AbstractArray%7BT,1%7D%7D,%20Tuple%7BAny,Any,Any,AbstractArray%7BT,1%7D,Any%7D%7D%20where%20T) implemented in

> **[GitHub - baggepinnen/SpectralDistances.jl: Measure the distance between two...](https://github.com/baggepinnen/SpectralDistances.jl)**
>
> Measure the distance between two spectra/signals using optimal transport and related metrics - GitHub - baggepinnen/SpectralDistances.jl: Measure the distance between two spectra/signals using opti...

Do you know how performance and stability of your julia implementations of sinkhorn compare against POT?

---

<div class="post-metadata">

**Author:** ![zsteve](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zsteve/32/14841_2.png) [@zsteve](https://discourse.julialang.org/u/zsteve)\
**Post date:** [May 18, 2020, 3:18am UTC](https://discourse.julialang.org/t/ann-optimaltransport-jl-optimal-transport-algorithms-for-julia/39447/3 "2020-05-18T03:18:37Z")

</div>

Good question! In terms of performance, comparing Julia sinkhorn to the POT implementation on 1000x1000 problem gives me the following:

Julia:

```julia
using OptimalTransport
using Distances
using LinearAlgebra

N = 1000; M = 1000
μ_spt = rand(N)
ν_spt = rand(M)

μ = ones(size(μ_spt, 1))
ν = ones(size(ν_spt, 1))

C = pairwise(Euclidean(), μ_spt', ν_spt').^2
ϵ = 0.01

using BenchmarkTools
@benchmark γ = sinkhorn(μ, ν, C, ϵ)

```

Output:

```julia
julia> @benchmark sinkhorn(μ, ν, C, ϵ)
BenchmarkTools.Trial:
  memory estimate: 27.24 MiB
  allocs estimate: 572
  --------------
  minimum time: 259.265 ms (0.00% GC)
  median time: 286.214 ms (0.20% GC)
  mean time: 299.338 ms (2.71% GC)
  maximum time: 355.400 ms (4.59% GC)
  --------------
  samples: 17
  evals/sample: 1

```

POT:

```julia
import ot
import numpy as np

N = 1000
mu = np.random.rand(N, 1)
nu = np.random.rand(N, 1)
C = ot.utils.dist(mu, nu)
eps = 0.01

%timeit ot.sinkhorn(np.ones(N), np.ones(N), C, eps)

```

Output:

```julia
In [8]: %timeit ot.sinkhorn(np.ones(N), np.ones(N), C, eps)
577 ms ± 12.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

```

Edits: realised there was a bug in some of the code I ran 😕 my brain obviously not working on Sunday

---

<div class="post-metadata">

**Author:** ![evanfields](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evanfields/32/1744_2.png) [@evanfields](https://discourse.julialang.org/u/evanfields)\
**Post date:** [May 18, 2020, 11:23pm UTC](https://discourse.julialang.org/t/ann-optimaltransport-jl-optimal-transport-algorithms-for-julia/39447/4 "2020-05-18T23:23:40Z")

</div>

I’m delighted to see this! For mostly personal philosophical reasons I’m a big optimal transport fan and hope to see the tools become more widespread.

---

<div class="post-metadata">

**Author:** ![jaimece](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jaimece/32/46345_2.png) [@jaimece](https://discourse.julialang.org/u/jaimece)\
**Post date:** [March 17, 2026, 11:41am UTC](https://discourse.julialang.org/t/ann-optimaltransport-jl-optimal-transport-algorithms-for-julia/39447/5 "2026-03-17T11:41:11Z")

</div>

Hi there,  
the package OptimalTransport.jl looks great, congratulations!  
Any plans to include solvers for Gromov-Wasserstein and Fused GW in the near future?  
They are implemented in POT, and it was sad to go back to Python just for using them.
