Skip to content

Commit 3392e8d

Browse files
Circle CICircle CI
authored andcommitted
CircleCI update of dev docs (1668).
1 parent 8f0ebd0 commit 3392e8d

374 files changed

Lines changed: 1284978 additions & 773769 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎master/.github/CODE_OF_CONDUCT.html‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!DOCTYPE html>
22
<html class="writer-html5" lang="en" >
33
<head>
4-
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
4+
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
55

66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>Code of Conduct &mdash; POT Python Optimal Transport 0.8.3dev documentation</title>
@@ -32,15 +32,19 @@
3232
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
3333
<div class="wy-side-scroll">
3434
<div class="wy-side-nav-search" >
35-
<a href="../index.html" class="icon icon-home"> POT Python Optimal Transport
36-
<img src="../_static/logo_dark.svg" class="logo" alt="Logo"/>
35+
36+
37+
38+
<a href="../index.html" class="icon icon-home">
39+
POT Python Optimal Transport
40+
<img src="../_static/logo_dark.svg" class="logo" alt="Logo"/>
3741
</a>
3842
<div class="version">
3943
0.8.3dev
4044
</div>
4145
<div role="search">
4246
<form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
43-
<input type="text" name="q" placeholder="Search docs" />
47+
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
4448
<input type="hidden" name="check_keywords" value="yes" />
4549
<input type="hidden" name="area" value="default" />
4650
</form>
@@ -78,7 +82,7 @@
7882
<div class="rst-content">
7983
<div role="navigation" aria-label="Page navigation">
8084
<ul class="wy-breadcrumbs">
81-
<li><a href="../index.html" class="icon icon-home"></a></li>
85+
<li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li>
8286
<li class="breadcrumb-item active">Code of Conduct</li>
8387
<li class="wy-breadcrumbs-aside">
8488
<a href="../_sources/.github/CODE_OF_CONDUCT.rst.txt" rel="nofollow"> View page source</a>

‎master/.github/CONTRIBUTING.html‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!DOCTYPE html>
22
<html class="writer-html5" lang="en" >
33
<head>
4-
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
4+
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.18.1: http://docutils.sourceforge.net/" />
55

66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>Contributing to POT &mdash; POT Python Optimal Transport 0.8.3dev documentation</title>
@@ -33,15 +33,19 @@
3333
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
3434
<div class="wy-side-scroll">
3535
<div class="wy-side-nav-search" >
36-
<a href="../index.html" class="icon icon-home"> POT Python Optimal Transport
37-
<img src="../_static/logo_dark.svg" class="logo" alt="Logo"/>
36+
37+
38+
39+
<a href="../index.html" class="icon icon-home">
40+
POT Python Optimal Transport
41+
<img src="../_static/logo_dark.svg" class="logo" alt="Logo"/>
3842
</a>
3943
<div class="version">
4044
0.8.3dev
4145
</div>
4246
<div role="search">
4347
<form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
44-
<input type="text" name="q" placeholder="Search docs" />
48+
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
4549
<input type="hidden" name="check_keywords" value="yes" />
4650
<input type="hidden" name="area" value="default" />
4751
</form>
@@ -78,7 +82,7 @@
7882
<div class="rst-content">
7983
<div role="navigation" aria-label="Page navigation">
8084
<ul class="wy-breadcrumbs">
81-
<li><a href="../index.html" class="icon icon-home"></a></li>
85+
<li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li>
8286
<li class="breadcrumb-item active">Contributing to POT</li>
8387
<li class="wy-breadcrumbs-aside">
8488
<a href="../_sources/.github/CONTRIBUTING.rst.txt" rel="nofollow"> View page source</a>
Binary file not shown.
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# -*- coding: utf-8 -*-
2+
r"""
3+
================================================
4+
Spherical Sliced-Wasserstein Embedding on Sphere
5+
================================================
6+
7+
Here, we aim at transforming samples into a uniform
8+
distribution on the sphere by minimizing SSW:
9+
10+
.. math::
11+
\min_{x} SSW_2(\nu, \frac{1}{n}\sum_{i=1}^n \delta_{x_i})
12+
13+
where :math:`\nu=\mathrm{Unif}(S^1)`.
14+
15+
"""
16+
17+
# Author: Clément Bonet <clement.bonet@univ-ubs.fr>
18+
#
19+
# License: MIT License
20+
21+
# sphinx_gallery_thumbnail_number = 3
22+
23+
import numpy as np
24+
import matplotlib.pyplot as pl
25+
import matplotlib.animation as animation
26+
import torch
27+
import torch.nn.functional as F
28+
29+
import ot
30+
31+
32+
# %%
33+
# Data generation
34+
# ---------------
35+
36+
torch.manual_seed(1)
37+
38+
N = 1000
39+
x0 = torch.rand(N, 3)
40+
x0 = F.normalize(x0, dim=-1)
41+
42+
43+
# %%
44+
# Plot data
45+
# ---------
46+
47+
def plot_sphere(ax):
48+
xlist = np.linspace(-1.0, 1.0, 50)
49+
ylist = np.linspace(-1.0, 1.0, 50)
50+
r = np.linspace(1.0, 1.0, 50)
51+
X, Y = np.meshgrid(xlist, ylist)
52+
53+
Z = np.sqrt(r**2 - X**2 - Y**2)
54+
55+
ax.plot_wireframe(X, Y, Z, color="gray", alpha=.3)
56+
ax.plot_wireframe(X, Y, -Z, color="gray", alpha=.3) # Now plot the bottom half
57+
58+
59+
# plot the distributions
60+
pl.figure(1)
61+
ax = pl.axes(projection='3d')
62+
plot_sphere(ax)
63+
ax.scatter(x0[:, 0], x0[:, 1], x0[:, 2], label='Data samples', alpha=0.5)
64+
ax.set_title('Data distribution')
65+
ax.legend()
66+
67+
68+
# %%
69+
# Gradient descent
70+
# ----------------
71+
72+
x = x0.clone()
73+
x.requires_grad_(True)
74+
75+
n_iter = 500
76+
lr = 100
77+
78+
losses = []
79+
xvisu = torch.zeros(n_iter, N, 3)
80+
81+
for i in range(n_iter):
82+
sw = ot.sliced_wasserstein_sphere_unif(x, n_projections=500)
83+
grad_x = torch.autograd.grad(sw, x)[0]
84+
85+
x = x - lr * grad_x
86+
x = F.normalize(x, p=2, dim=1)
87+
88+
losses.append(sw.item())
89+
xvisu[i, :, :] = x.detach().clone()
90+
91+
if i % 100 == 0:
92+
print("Iter: {:3d}, loss={}".format(i, losses[-1]))
93+
94+
pl.figure(1)
95+
pl.semilogy(losses)
96+
pl.grid()
97+
pl.title('SSW')
98+
pl.xlabel("Iterations")
99+
100+
101+
# %%
102+
# Plot trajectories of generated samples along iterations
103+
# -------------------------------------------------------
104+
105+
ivisu = [0, 25, 50, 75, 100, 150, 200, 350, 499]
106+
107+
fig = pl.figure(3, (10, 10))
108+
for i in range(9):
109+
# pl.subplot(3, 3, i + 1)
110+
# ax = pl.axes(projection='3d')
111+
ax = fig.add_subplot(3, 3, i + 1, projection='3d')
112+
plot_sphere(ax)
113+
ax.scatter(xvisu[ivisu[i], :, 0], xvisu[ivisu[i], :, 1], xvisu[ivisu[i], :, 2], label='Data samples', alpha=0.5)
114+
ax.set_title('Iter. {}'.format(ivisu[i]))
115+
#ax.axis("off")
116+
if i == 0:
117+
ax.legend()
118+
119+
120+
# %%
121+
# Animate trajectories of generated samples along iteration
122+
# -------------------------------------------------------
123+
124+
pl.figure(4, (8, 8))
125+
126+
127+
def _update_plot(i):
128+
i = 3 * i
129+
pl.clf()
130+
ax = pl.axes(projection='3d')
131+
plot_sphere(ax)
132+
ax.scatter(xvisu[i, :, 0], xvisu[i, :, 1], xvisu[i, :, 2], label='Data samples$', alpha=0.5)
133+
ax.axis("off")
134+
ax.set_xlim((-1.5, 1.5))
135+
ax.set_ylim((-1.5, 1.5))
136+
ax.set_title('Iter. {}'.format(i))
137+
return 1
138+
139+
140+
print(xvisu.shape)
141+
142+
i = 0
143+
ax = pl.axes(projection='3d')
144+
plot_sphere(ax)
145+
ax.scatter(xvisu[i, :, 0], xvisu[i, :, 1], xvisu[i, :, 2], label='Data samples from $G\#\mu_n$', alpha=0.5)
146+
ax.axis("off")
147+
ax.set_xlim((-1.5, 1.5))
148+
ax.set_ylim((-1.5, 1.5))
149+
ax.set_title('Iter. {}'.format(ivisu[i]))
150+
151+
152+
ani = animation.FuncAnimation(pl.gcf(), _update_plot, n_iter // 5, interval=100, repeat_delay=2000)
153+
# %%
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"metadata": {
7+
"collapsed": false
8+
},
9+
"outputs": [],
10+
"source": [
11+
"%matplotlib inline"
12+
]
13+
},
14+
{
15+
"cell_type": "markdown",
16+
"metadata": {},
17+
"source": [
18+
"\n# OT distance on the Circle\n\nShows how to compute the Wasserstein distance on the circle\n"
19+
]
20+
},
21+
{
22+
"cell_type": "code",
23+
"execution_count": null,
24+
"metadata": {
25+
"collapsed": false
26+
},
27+
"outputs": [],
28+
"source": [
29+
"# Author: Cl\u00e9ment Bonet <clement.bonet@univ-ubs.fr>\n#\n# License: MIT License\n\n# sphinx_gallery_thumbnail_number = 2\n\nimport numpy as np\nimport matplotlib.pylab as pl\nimport ot\n\nfrom scipy.special import iv"
30+
]
31+
},
32+
{
33+
"cell_type": "markdown",
34+
"metadata": {},
35+
"source": [
36+
"## Plot data\n\n"
37+
]
38+
},
39+
{
40+
"cell_type": "code",
41+
"execution_count": null,
42+
"metadata": {
43+
"collapsed": false
44+
},
45+
"outputs": [],
46+
"source": [
47+
"def pdf_von_Mises(theta, mu, kappa):\n pdf = np.exp(kappa * np.cos(theta - mu)) / (2.0 * np.pi * iv(0, kappa))\n return pdf\n\n\nt = np.linspace(0, 2 * np.pi, 1000, endpoint=False)\n\nmu1 = 1\nkappa1 = 20\n\nmu_targets = np.linspace(mu1, mu1 + 2 * np.pi, 10)\n\n\npdf1 = pdf_von_Mises(t, mu1, kappa1)\n\n\npl.figure(1)\nfor k, mu in enumerate(mu_targets):\n pdf_t = pdf_von_Mises(t, mu, kappa1)\n if k == 0:\n label = \"Source distributions\"\n else:\n label = None\n pl.plot(t / (2 * np.pi), pdf_t, c='b', label=label)\n\npl.plot(t / (2 * np.pi), pdf1, c=\"r\", label=\"Target distribution\")\npl.legend()\n\nmu2 = 0\nkappa2 = kappa1\n\nx1 = np.random.vonmises(mu1, kappa1, size=(10,)) + np.pi\nx2 = np.random.vonmises(mu2, kappa2, size=(10,)) + np.pi\n\nangles = np.linspace(0, 2 * np.pi, 150)\n\npl.figure(2)\npl.plot(np.cos(angles), np.sin(angles), c=\"k\")\npl.xlim(-1.25, 1.25)\npl.ylim(-1.25, 1.25)\npl.scatter(np.cos(x1), np.sin(x1), c=\"b\")\npl.scatter(np.cos(x2), np.sin(x2), c=\"r\")"
48+
]
49+
},
50+
{
51+
"cell_type": "markdown",
52+
"metadata": {},
53+
"source": [
54+
"## Compare the Euclidean Wasserstein distance with the Wasserstein distance on the circle\nThis examples illustrates the periodicity of the Wasserstein distance on the circle.\nWe choose as target distribution a von Mises distribution with mean $\\mu_{\\mathrm{target}}$\nand $\\kappa=20$. Then, we compare the distances with samples obtained from a von Mises distribution\nwith parameters $\\mu_{\\mathrm{source}}$ and $\\kappa=20$.\nThe Wasserstein distance on the circle takes into account the periodicity\nand attains its maximum in $\\mu_{\\mathrm{target}}+1$ (the antipodal point) contrary to the\nEuclidean version.\n\n"
55+
]
56+
},
57+
{
58+
"cell_type": "code",
59+
"execution_count": null,
60+
"metadata": {
61+
"collapsed": false
62+
},
63+
"outputs": [],
64+
"source": [
65+
"mu_targets = np.linspace(0, 2 * np.pi, 200)\nxs = np.random.vonmises(mu1 - np.pi, kappa1, size=(500,)) + np.pi\n\nn_try = 5\n\nxts = np.zeros((n_try, 200, 500))\nfor i in range(n_try):\n for k, mu in enumerate(mu_targets):\n # np.random.vonmises deals with data on [-pi, pi[\n xt = np.random.vonmises(mu - np.pi, kappa2, size=(500,)) + np.pi\n xts[i, k] = xt\n\n# Put data on S^1=[0,1[\nxts2 = xts / (2 * np.pi)\nxs2 = np.concatenate([xs[None] for k in range(200)], axis=0) / (2 * np.pi)\n\nL_w2_circle = np.zeros((n_try, 200))\nL_w2 = np.zeros((n_try, 200))\n\nfor i in range(n_try):\n w2_circle = ot.wasserstein_circle(xs2.T, xts2[i].T, p=2)\n w2 = ot.wasserstein_1d(xs2.T, xts2[i].T, p=2)\n\n L_w2_circle[i] = w2_circle\n L_w2[i] = w2\n\nm_w2_circle = np.mean(L_w2_circle, axis=0)\nstd_w2_circle = np.std(L_w2_circle, axis=0)\n\nm_w2 = np.mean(L_w2, axis=0)\nstd_w2 = np.std(L_w2, axis=0)\n\npl.figure(1)\npl.plot(mu_targets / (2 * np.pi), m_w2_circle, label=\"Wasserstein circle\")\npl.fill_between(mu_targets / (2 * np.pi), m_w2_circle - 2 * std_w2_circle, m_w2_circle + 2 * std_w2_circle, alpha=0.5)\npl.plot(mu_targets / (2 * np.pi), m_w2, label=\"Euclidean Wasserstein\")\npl.fill_between(mu_targets / (2 * np.pi), m_w2 - 2 * std_w2, m_w2 + 2 * std_w2, alpha=0.5)\npl.vlines(x=[mu1 / (2 * np.pi)], ymin=0, ymax=np.max(w2), linestyle=\"--\", color=\"k\", label=r\"$\\mu_{\\mathrm{target}}$\")\npl.legend()\npl.xlabel(r\"$\\mu_{\\mathrm{source}}$\")\npl.show()"
66+
]
67+
},
68+
{
69+
"cell_type": "markdown",
70+
"metadata": {},
71+
"source": [
72+
"## Wasserstein distance between von Mises and uniform for different kappa\nWhen $\\kappa=0$, the von Mises distribution is the uniform distribution on $S^1$.\n\n"
73+
]
74+
},
75+
{
76+
"cell_type": "code",
77+
"execution_count": null,
78+
"metadata": {
79+
"collapsed": false
80+
},
81+
"outputs": [],
82+
"source": [
83+
"kappas = np.logspace(-5, 2, 100)\nn_try = 20\n\nxts = np.zeros((n_try, 100, 500))\nfor i in range(n_try):\n for k, kappa in enumerate(kappas):\n # np.random.vonmises deals with data on [-pi, pi[\n xt = np.random.vonmises(0, kappa, size=(500,)) + np.pi\n xts[i, k] = xt / (2 * np.pi)\n\nL_w2 = np.zeros((n_try, 100))\nfor i in range(n_try):\n L_w2[i] = ot.semidiscrete_wasserstein2_unif_circle(xts[i].T)\n\nm_w2 = np.mean(L_w2, axis=0)\nstd_w2 = np.std(L_w2, axis=0)\n\npl.figure(1)\npl.plot(kappas, m_w2)\npl.fill_between(kappas, m_w2 - std_w2, m_w2 + std_w2, alpha=0.5)\npl.title(r\"Evolution of $W_2^2(vM(0,\\kappa), Unif(S^1))$\")\npl.xlabel(r\"$\\kappa$\")\npl.show()"
84+
]
85+
}
86+
],
87+
"metadata": {
88+
"kernelspec": {
89+
"display_name": "Python 3",
90+
"language": "python",
91+
"name": "python3"
92+
},
93+
"language_info": {
94+
"codemirror_mode": {
95+
"name": "ipython",
96+
"version": 3
97+
},
98+
"file_extension": ".py",
99+
"mimetype": "text/x-python",
100+
"name": "python",
101+
"nbconvert_exporter": "python",
102+
"pygments_lexer": "ipython3",
103+
"version": "3.9.16"
104+
}
105+
},
106+
"nbformat": 4,
107+
"nbformat_minor": 0
108+
}
Binary file not shown.

0 commit comments

Comments
 (0)