From ab5918b2e2dc88a3520c059e6a79a6f81959381e Mon Sep 17 00:00:00 2001 From: Rémi Flamary Date: Wed, 30 Aug 2017 17:02:59 +0200 Subject: add files and notebooks --- .../images/sphx_glr_plot_otda_classes_001.png | Bin 0 -> 50114 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png (limited to 'docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png') diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png new file mode 100644 index 0000000..45a823d Binary files /dev/null and b/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png differ -- cgit v1.2.3 From 062071b20d1d40c64bb619931bd11bd28e780485 Mon Sep 17 00:00:00 2001 From: Rémi Flamary Date: Fri, 1 Sep 2017 15:31:44 +0200 Subject: update example with rst titles --- .gitignore | 2 - .../source/auto_examples/auto_examples_jupyter.zip | Bin 91095 -> 70410 bytes docs/source/auto_examples/auto_examples_python.zip | Bin 62950 -> 46653 bytes docs/source/auto_examples/demo_OT_1D_test.ipynb | 54 ---- docs/source/auto_examples/demo_OT_1D_test.py | 71 ----- docs/source/auto_examples/demo_OT_1D_test.rst | 99 ------ .../auto_examples/demo_OT_2D_sampleslarge.ipynb | 54 ---- .../auto_examples/demo_OT_2D_sampleslarge.py | 78 ----- .../auto_examples/demo_OT_2D_sampleslarge.rst | 106 ------- .../images/sphx_glr_plot_OTDA_2D_001.png | Bin 52753 -> 0 bytes .../images/sphx_glr_plot_OTDA_2D_002.png | Bin 87798 -> 0 bytes .../images/sphx_glr_plot_OTDA_2D_003.png | Bin 167396 -> 0 bytes .../images/sphx_glr_plot_OTDA_2D_004.png | Bin 82929 -> 0 bytes .../images/sphx_glr_plot_OTDA_classes_001.png | Bin 53561 -> 0 bytes .../images/sphx_glr_plot_OTDA_classes_004.png | Bin 193523 -> 0 bytes .../images/sphx_glr_plot_OTDA_color_images_001.png | Bin 237854 -> 0 bytes .../images/sphx_glr_plot_OTDA_color_images_002.png | Bin 472911 -> 0 bytes .../images/sphx_glr_plot_OTDA_mapping_001.png | Bin 44168 -> 0 bytes .../images/sphx_glr_plot_OTDA_mapping_002.png | Bin 111565 -> 0 bytes ...sphx_glr_plot_OTDA_mapping_color_images_001.png | Bin 237854 -> 0 bytes ...sphx_glr_plot_OTDA_mapping_color_images_002.png | Bin 429859 -> 0 bytes .../images/sphx_glr_plot_OT_1D_003.png | Bin 16995 -> 0 bytes .../images/sphx_glr_plot_OT_1D_004.png | Bin 18923 -> 0 bytes .../images/sphx_glr_plot_OT_2D_samples_001.png | Bin 21092 -> 20707 bytes .../images/sphx_glr_plot_OT_2D_samples_002.png | Bin 21310 -> 21335 bytes .../images/sphx_glr_plot_OT_2D_samples_003.png | Bin 9625 -> 0 bytes .../images/sphx_glr_plot_OT_2D_samples_004.png | Bin 82376 -> 0 bytes .../images/sphx_glr_plot_OT_2D_samples_005.png | Bin 13913 -> 9613 bytes .../images/sphx_glr_plot_OT_2D_samples_006.png | Bin 102963 -> 83657 bytes .../images/sphx_glr_plot_OT_L1_vs_L2_001.png | Bin 14117 -> 11710 bytes .../images/sphx_glr_plot_OT_L1_vs_L2_002.png | Bin 18696 -> 17184 bytes .../images/sphx_glr_plot_OT_L1_vs_L2_003.png | Bin 21300 -> 38780 bytes .../images/sphx_glr_plot_OT_L1_vs_L2_005.png | Bin 17184 -> 38780 bytes .../auto_examples/images/sphx_glr_plot_WDA_001.png | Bin 56060 -> 55483 bytes .../auto_examples/images/sphx_glr_plot_WDA_002.png | Bin 90982 -> 0 bytes .../images/sphx_glr_plot_barycenter_1D_003.png | Bin 108687 -> 41555 bytes .../images/sphx_glr_plot_compute_emd_002.png | Bin 38746 -> 0 bytes .../images/sphx_glr_plot_optim_OTreg_005.png | Bin 20440 -> 0 bytes .../images/sphx_glr_plot_otda_classes_001.png | Bin 50114 -> 49949 bytes .../images/sphx_glr_plot_otda_classes_003.png | Bin 194170 -> 189153 bytes .../images/sphx_glr_plot_otda_color_images_001.png | Bin 144957 -> 144945 bytes .../images/sphx_glr_plot_otda_color_images_003.png | Bin 50401 -> 50403 bytes .../images/sphx_glr_plot_otda_color_images_005.png | Bin 234337 -> 234386 bytes .../images/sphx_glr_plot_otda_d2_001.png | Bin 130439 -> 131873 bytes .../images/sphx_glr_plot_otda_d2_003.png | Bin 224757 -> 240262 bytes .../images/sphx_glr_plot_otda_d2_006.png | Bin 99742 -> 104502 bytes .../images/sphx_glr_plot_otda_mapping_001.png | Bin 35810 -> 37940 bytes .../images/sphx_glr_plot_otda_mapping_003.png | Bin 71391 -> 76017 bytes ...phx_glr_plot_otda_mapping_colors_images_001.png | Bin 165592 -> 165589 bytes ...phx_glr_plot_otda_mapping_colors_images_003.png | Bin 80722 -> 80727 bytes ...phx_glr_plot_otda_mapping_colors_images_004.png | Bin 541483 -> 541463 bytes .../images/thumb/sphx_glr_plot_OTDA_2D_thumb.png | Bin 34799 -> 0 bytes .../thumb/sphx_glr_plot_OTDA_classes_thumb.png | Bin 34581 -> 0 bytes .../sphx_glr_plot_OTDA_color_images_thumb.png | Bin 52919 -> 0 bytes ...hx_glr_plot_OTDA_mapping_color_images_thumb.png | Bin 52919 -> 0 bytes .../thumb/sphx_glr_plot_OTDA_mapping_thumb.png | Bin 26370 -> 0 bytes .../images/thumb/sphx_glr_plot_OT_1D_thumb.png | Bin 18227 -> 18222 bytes .../thumb/sphx_glr_plot_OT_2D_samples_thumb.png | Bin 23844 -> 22370 bytes .../thumb/sphx_glr_plot_OT_L1_vs_L2_thumb.png | Bin 16407 -> 10935 bytes .../images/thumb/sphx_glr_plot_OT_conv_thumb.png | Bin 2894 -> 0 bytes .../images/thumb/sphx_glr_plot_WDA_thumb.png | Bin 87834 -> 88848 bytes .../thumb/sphx_glr_plot_barycenter_1D_thumb.png | Bin 16522 -> 16522 bytes .../thumb/sphx_glr_plot_compute_emd_thumb.png | Bin 80805 -> 80806 bytes .../thumb/sphx_glr_plot_optim_OTreg_thumb.png | Bin 21750 -> 3101 bytes .../thumb/sphx_glr_plot_otda_classes_thumb.png | Bin 30152 -> 29948 bytes .../sphx_glr_plot_otda_color_images_thumb.png | Bin 51085 -> 51088 bytes .../images/thumb/sphx_glr_plot_otda_d2_thumb.png | Bin 52925 -> 54746 bytes ...x_glr_plot_otda_mapping_colors_images_thumb.png | Bin 58315 -> 58321 bytes .../thumb/sphx_glr_plot_otda_mapping_thumb.png | Bin 18620 -> 19281 bytes ...phx_glr_test_OT_2D_samples_stabilized_thumb.png | Bin 3101 -> 0 bytes docs/source/auto_examples/index.rst | 64 ++-- docs/source/auto_examples/plot_OTDA_2D.ipynb | 54 ---- docs/source/auto_examples/plot_OTDA_2D.py | 120 ------- docs/source/auto_examples/plot_OTDA_2D.rst | 175 ---------- docs/source/auto_examples/plot_OTDA_classes.ipynb | 54 ---- docs/source/auto_examples/plot_OTDA_classes.py | 112 ------- docs/source/auto_examples/plot_OTDA_classes.rst | 190 ----------- .../auto_examples/plot_OTDA_color_images.ipynb | 54 ---- .../source/auto_examples/plot_OTDA_color_images.py | 145 --------- .../auto_examples/plot_OTDA_color_images.rst | 191 ----------- docs/source/auto_examples/plot_OTDA_mapping.ipynb | 54 ---- docs/source/auto_examples/plot_OTDA_mapping.py | 110 ------- docs/source/auto_examples/plot_OTDA_mapping.rst | 186 ----------- .../plot_OTDA_mapping_color_images.ipynb | 54 ---- .../plot_OTDA_mapping_color_images.py | 158 ---------- .../plot_OTDA_mapping_color_images.rst | 246 --------------- docs/source/auto_examples/plot_OT_1D.ipynb | 4 +- docs/source/auto_examples/plot_OT_1D.py | 5 +- docs/source/auto_examples/plot_OT_1D.rst | 9 +- docs/source/auto_examples/plot_OT_2D_samples.ipynb | 76 ++++- docs/source/auto_examples/plot_OT_2D_samples.py | 18 ++ docs/source/auto_examples/plot_OT_2D_samples.rst | 132 ++++++-- docs/source/auto_examples/plot_OT_L1_vs_L2.ipynb | 76 ++++- docs/source/auto_examples/plot_OT_L1_vs_L2.py | 280 ++++++++++------ docs/source/auto_examples/plot_OT_L1_vs_L2.rst | 351 ++++++++++++++------- docs/source/auto_examples/plot_OT_conv.ipynb | 54 ---- docs/source/auto_examples/plot_OT_conv.py | 200 ------------ docs/source/auto_examples/plot_OT_conv.rst | 241 -------------- docs/source/auto_examples/plot_WDA.ipynb | 94 +++++- docs/source/auto_examples/plot_WDA.py | 27 ++ docs/source/auto_examples/plot_WDA.rst | 172 ++++++---- docs/source/auto_examples/plot_barycenter_1D.ipynb | 76 ++++- docs/source/auto_examples/plot_barycenter_1D.py | 23 ++ docs/source/auto_examples/plot_barycenter_1D.rst | 113 +++++-- docs/source/auto_examples/plot_compute_emd.ipynb | 76 ++++- docs/source/auto_examples/plot_compute_emd.py | 30 +- docs/source/auto_examples/plot_compute_emd.rst | 100 ++++-- docs/source/auto_examples/plot_optim_OTreg.ipynb | 8 +- docs/source/auto_examples/plot_optim_OTreg.py | 23 +- docs/source/auto_examples/plot_optim_OTreg.rst | 29 +- docs/source/auto_examples/plot_otda_classes.rst | 46 +-- .../auto_examples/plot_otda_color_images.ipynb | 18 +- .../source/auto_examples/plot_otda_color_images.py | 66 ++-- .../auto_examples/plot_otda_color_images.rst | 90 +++--- docs/source/auto_examples/plot_otda_d2.rst | 4 +- docs/source/auto_examples/plot_otda_mapping.ipynb | 14 +- docs/source/auto_examples/plot_otda_mapping.py | 35 +- docs/source/auto_examples/plot_otda_mapping.rst | 105 +++--- .../plot_otda_mapping_colors_images.ipynb | 8 +- .../plot_otda_mapping_colors_images.py | 15 +- .../plot_otda_mapping_colors_images.rst | 85 ++--- docs/source/conf.py | 4 +- docs/source/examples.rst | 39 --- examples/README.txt | 2 + examples/plot_OT_1D.py | 2 +- examples/plot_OT_2D_samples.py | 3 + examples/plot_OT_L1_vs_L2.py | 280 ++++++++++------ examples/plot_barycenter_1D.py | 17 +- examples/plot_compute_emd.py | 4 + examples/plot_optim_OTreg.py | 4 +- examples/plot_otda_mapping.py | 10 +- examples/plot_otda_mapping_colors_images.py | 6 +- 132 files changed, 1849 insertions(+), 3656 deletions(-) delete mode 100644 docs/source/auto_examples/demo_OT_1D_test.ipynb delete mode 100644 docs/source/auto_examples/demo_OT_1D_test.py delete mode 100644 docs/source/auto_examples/demo_OT_1D_test.rst delete mode 100644 docs/source/auto_examples/demo_OT_2D_sampleslarge.ipynb delete mode 100644 docs/source/auto_examples/demo_OT_2D_sampleslarge.py delete mode 100644 docs/source/auto_examples/demo_OT_2D_sampleslarge.rst delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_001.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_002.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_003.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_004.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OTDA_classes_001.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OTDA_classes_004.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OTDA_color_images_001.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OTDA_color_images_002.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_001.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_002.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_color_images_001.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_color_images_002.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OT_1D_003.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OT_1D_004.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_003.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_004.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_WDA_002.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_compute_emd_002.png delete mode 100644 docs/source/auto_examples/images/sphx_glr_plot_optim_OTreg_005.png delete mode 100644 docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_2D_thumb.png delete mode 100644 docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_classes_thumb.png delete mode 100644 docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_color_images_thumb.png delete mode 100644 docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_mapping_color_images_thumb.png delete mode 100644 docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_mapping_thumb.png delete mode 100644 docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_conv_thumb.png delete mode 100644 docs/source/auto_examples/images/thumb/sphx_glr_test_OT_2D_samples_stabilized_thumb.png delete mode 100644 docs/source/auto_examples/plot_OTDA_2D.ipynb delete mode 100644 docs/source/auto_examples/plot_OTDA_2D.py delete mode 100644 docs/source/auto_examples/plot_OTDA_2D.rst delete mode 100644 docs/source/auto_examples/plot_OTDA_classes.ipynb delete mode 100644 docs/source/auto_examples/plot_OTDA_classes.py delete mode 100644 docs/source/auto_examples/plot_OTDA_classes.rst delete mode 100644 docs/source/auto_examples/plot_OTDA_color_images.ipynb delete mode 100644 docs/source/auto_examples/plot_OTDA_color_images.py delete mode 100644 docs/source/auto_examples/plot_OTDA_color_images.rst delete mode 100644 docs/source/auto_examples/plot_OTDA_mapping.ipynb delete mode 100644 docs/source/auto_examples/plot_OTDA_mapping.py delete mode 100644 docs/source/auto_examples/plot_OTDA_mapping.rst delete mode 100644 docs/source/auto_examples/plot_OTDA_mapping_color_images.ipynb delete mode 100644 docs/source/auto_examples/plot_OTDA_mapping_color_images.py delete mode 100644 docs/source/auto_examples/plot_OTDA_mapping_color_images.rst delete mode 100644 docs/source/auto_examples/plot_OT_conv.ipynb delete mode 100644 docs/source/auto_examples/plot_OT_conv.py delete mode 100644 docs/source/auto_examples/plot_OT_conv.rst delete mode 100644 docs/source/examples.rst (limited to 'docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png') diff --git a/.gitignore b/.gitignore index 42a9aad..887a164 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,6 @@ __pycache__/ .spyproject # sphinx-gallery temp files -docs/source/auto_examples/*.pickle -docs/source/auto_examples/*.md5 docs/auto_examples/ docs/modules/ diff --git a/docs/source/auto_examples/auto_examples_jupyter.zip b/docs/source/auto_examples/auto_examples_jupyter.zip index 92aa027..96bc0bc 100644 Binary files a/docs/source/auto_examples/auto_examples_jupyter.zip and b/docs/source/auto_examples/auto_examples_jupyter.zip differ diff --git a/docs/source/auto_examples/auto_examples_python.zip b/docs/source/auto_examples/auto_examples_python.zip index bc41a8c..6241b92 100644 Binary files a/docs/source/auto_examples/auto_examples_python.zip and b/docs/source/auto_examples/auto_examples_python.zip differ diff --git a/docs/source/auto_examples/demo_OT_1D_test.ipynb b/docs/source/auto_examples/demo_OT_1D_test.ipynb deleted file mode 100644 index 87317ea..0000000 --- a/docs/source/auto_examples/demo_OT_1D_test.ipynb +++ /dev/null @@ -1,54 +0,0 @@ -{ - "nbformat_minor": 0, - "nbformat": 4, - "cells": [ - { - "execution_count": null, - "cell_type": "code", - "source": [ - "%matplotlib inline" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - }, - { - "source": [ - "\nDemo for 1D optimal transport\n\n@author: rflamary\n\n" - ], - "cell_type": "markdown", - "metadata": {} - }, - { - "execution_count": null, - "cell_type": "code", - "source": [ - "import numpy as np\nimport matplotlib.pylab as pl\nimport ot\nfrom ot.datasets import get_1D_gauss as gauss\n\n\n#%% parameters\n\nn=100 # nb bins\n\n# bin positions\nx=np.arange(n,dtype=np.float64)\n\n# Gaussian distributions\na=gauss(n,m=n*.2,s=5) # m= mean, s= std\nb=gauss(n,m=n*.6,s=10)\n\n# loss matrix\nM=ot.dist(x.reshape((n,1)),x.reshape((n,1)))\nM/=M.max()\n\n#%% plot the distributions\n\npl.figure(1)\npl.plot(x,a,'b',label='Source distribution')\npl.plot(x,b,'r',label='Target distribution')\npl.legend()\n\n#%% plot distributions and loss matrix\n\npl.figure(2)\not.plot.plot1D_mat(a,b,M,'Cost matrix M')\n\n#%% EMD\n\nG0=ot.emd(a,b,M)\n\npl.figure(3)\not.plot.plot1D_mat(a,b,G0,'OT matrix G0')\n\n#%% Sinkhorn\n\nlambd=1e-3\nGs=ot.sinkhorn(a,b,M,lambd,verbose=True)\n\npl.figure(4)\not.plot.plot1D_mat(a,b,Gs,'OT matrix Sinkhorn')\n\n#%% Sinkhorn\n\nlambd=1e-4\nGss,log=ot.bregman.sinkhorn_stabilized(a,b,M,lambd,verbose=True,log=True)\nGss2,log2=ot.bregman.sinkhorn_stabilized(a,b,M,lambd,verbose=True,log=True,warmstart=log['warmstart'])\n\npl.figure(5)\not.plot.plot1D_mat(a,b,Gss,'OT matrix Sinkhorn stabilized')\n\n#%% Sinkhorn\n\nlambd=1e-11\nGss=ot.bregman.sinkhorn_epsilon_scaling(a,b,M,lambd,verbose=True)\n\npl.figure(5)\not.plot.plot1D_mat(a,b,Gss,'OT matrix Sinkhorn stabilized')" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 2", - "name": "python2", - "language": "python" - }, - "language_info": { - "mimetype": "text/x-python", - "nbconvert_exporter": "python", - "name": "python", - "file_extension": ".py", - "version": "2.7.12", - "pygments_lexer": "ipython2", - "codemirror_mode": { - "version": 2, - "name": "ipython" - } - } - } -} \ No newline at end of file diff --git a/docs/source/auto_examples/demo_OT_1D_test.py b/docs/source/auto_examples/demo_OT_1D_test.py deleted file mode 100644 index 9edc377..0000000 --- a/docs/source/auto_examples/demo_OT_1D_test.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Demo for 1D optimal transport - -@author: rflamary -""" - -import numpy as np -import matplotlib.pylab as pl -import ot -from ot.datasets import get_1D_gauss as gauss - - -#%% parameters - -n=100 # nb bins - -# bin positions -x=np.arange(n,dtype=np.float64) - -# Gaussian distributions -a=gauss(n,m=n*.2,s=5) # m= mean, s= std -b=gauss(n,m=n*.6,s=10) - -# loss matrix -M=ot.dist(x.reshape((n,1)),x.reshape((n,1))) -M/=M.max() - -#%% plot the distributions - -pl.figure(1) -pl.plot(x,a,'b',label='Source distribution') -pl.plot(x,b,'r',label='Target distribution') -pl.legend() - -#%% plot distributions and loss matrix - -pl.figure(2) -ot.plot.plot1D_mat(a,b,M,'Cost matrix M') - -#%% EMD - -G0=ot.emd(a,b,M) - -pl.figure(3) -ot.plot.plot1D_mat(a,b,G0,'OT matrix G0') - -#%% Sinkhorn - -lambd=1e-3 -Gs=ot.sinkhorn(a,b,M,lambd,verbose=True) - -pl.figure(4) -ot.plot.plot1D_mat(a,b,Gs,'OT matrix Sinkhorn') - -#%% Sinkhorn - -lambd=1e-4 -Gss,log=ot.bregman.sinkhorn_stabilized(a,b,M,lambd,verbose=True,log=True) -Gss2,log2=ot.bregman.sinkhorn_stabilized(a,b,M,lambd,verbose=True,log=True,warmstart=log['warmstart']) - -pl.figure(5) -ot.plot.plot1D_mat(a,b,Gss,'OT matrix Sinkhorn stabilized') - -#%% Sinkhorn - -lambd=1e-11 -Gss=ot.bregman.sinkhorn_epsilon_scaling(a,b,M,lambd,verbose=True) - -pl.figure(5) -ot.plot.plot1D_mat(a,b,Gss,'OT matrix Sinkhorn stabilized') diff --git a/docs/source/auto_examples/demo_OT_1D_test.rst b/docs/source/auto_examples/demo_OT_1D_test.rst deleted file mode 100644 index aebeb1d..0000000 --- a/docs/source/auto_examples/demo_OT_1D_test.rst +++ /dev/null @@ -1,99 +0,0 @@ - - -.. _sphx_glr_auto_examples_demo_OT_1D_test.py: - - -Demo for 1D optimal transport - -@author: rflamary - - - -.. code-block:: python - - - import numpy as np - import matplotlib.pylab as pl - import ot - from ot.datasets import get_1D_gauss as gauss - - - #%% parameters - - n=100 # nb bins - - # bin positions - x=np.arange(n,dtype=np.float64) - - # Gaussian distributions - a=gauss(n,m=n*.2,s=5) # m= mean, s= std - b=gauss(n,m=n*.6,s=10) - - # loss matrix - M=ot.dist(x.reshape((n,1)),x.reshape((n,1))) - M/=M.max() - - #%% plot the distributions - - pl.figure(1) - pl.plot(x,a,'b',label='Source distribution') - pl.plot(x,b,'r',label='Target distribution') - pl.legend() - - #%% plot distributions and loss matrix - - pl.figure(2) - ot.plot.plot1D_mat(a,b,M,'Cost matrix M') - - #%% EMD - - G0=ot.emd(a,b,M) - - pl.figure(3) - ot.plot.plot1D_mat(a,b,G0,'OT matrix G0') - - #%% Sinkhorn - - lambd=1e-3 - Gs=ot.sinkhorn(a,b,M,lambd,verbose=True) - - pl.figure(4) - ot.plot.plot1D_mat(a,b,Gs,'OT matrix Sinkhorn') - - #%% Sinkhorn - - lambd=1e-4 - Gss,log=ot.bregman.sinkhorn_stabilized(a,b,M,lambd,verbose=True,log=True) - Gss2,log2=ot.bregman.sinkhorn_stabilized(a,b,M,lambd,verbose=True,log=True,warmstart=log['warmstart']) - - pl.figure(5) - ot.plot.plot1D_mat(a,b,Gss,'OT matrix Sinkhorn stabilized') - - #%% Sinkhorn - - lambd=1e-11 - Gss=ot.bregman.sinkhorn_epsilon_scaling(a,b,M,lambd,verbose=True) - - pl.figure(5) - ot.plot.plot1D_mat(a,b,Gss,'OT matrix Sinkhorn stabilized') - -**Total running time of the script:** ( 0 minutes 0.000 seconds) - - - -.. container:: sphx-glr-footer - - - .. container:: sphx-glr-download - - :download:`Download Python source code: demo_OT_1D_test.py ` - - - - .. container:: sphx-glr-download - - :download:`Download Jupyter notebook: demo_OT_1D_test.ipynb ` - -.. rst-class:: sphx-glr-signature - - `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/demo_OT_2D_sampleslarge.ipynb b/docs/source/auto_examples/demo_OT_2D_sampleslarge.ipynb deleted file mode 100644 index 584a936..0000000 --- a/docs/source/auto_examples/demo_OT_2D_sampleslarge.ipynb +++ /dev/null @@ -1,54 +0,0 @@ -{ - "nbformat_minor": 0, - "nbformat": 4, - "cells": [ - { - "execution_count": null, - "cell_type": "code", - "source": [ - "%matplotlib inline" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - }, - { - "source": [ - "\nDemo for 2D Optimal transport between empirical distributions\n\n@author: rflamary\n\n" - ], - "cell_type": "markdown", - "metadata": {} - }, - { - "execution_count": null, - "cell_type": "code", - "source": [ - "import numpy as np\nimport matplotlib.pylab as pl\nimport ot\n\n#%% parameters and data generation\n\nn=5000 # nb samples\n\nmu_s=np.array([0,0])\ncov_s=np.array([[1,0],[0,1]])\n\nmu_t=np.array([4,4])\ncov_t=np.array([[1,-.8],[-.8,1]])\n\nxs=ot.datasets.get_2D_samples_gauss(n,mu_s,cov_s)\nxt=ot.datasets.get_2D_samples_gauss(n,mu_t,cov_t)\n\na,b = ot.unif(n),ot.unif(n) # uniform distribution on samples\n\n# loss matrix\nM=ot.dist(xs,xt)\nM/=M.max()\n\n#%% plot samples\n\n#pl.figure(1)\n#pl.plot(xs[:,0],xs[:,1],'+b',label='Source samples')\n#pl.plot(xt[:,0],xt[:,1],'xr',label='Target samples')\n#pl.legend(loc=0)\n#pl.title('Source and traget distributions')\n#\n#pl.figure(2)\n#pl.imshow(M,interpolation='nearest')\n#pl.title('Cost matrix M')\n#\n\n#%% EMD\n\nG0=ot.emd(a,b,M)\n\n#pl.figure(3)\n#pl.imshow(G0,interpolation='nearest')\n#pl.title('OT matrix G0')\n#\n#pl.figure(4)\n#ot.plot.plot2D_samples_mat(xs,xt,G0,c=[.5,.5,1])\n#pl.plot(xs[:,0],xs[:,1],'+b',label='Source samples')\n#pl.plot(xt[:,0],xt[:,1],'xr',label='Target samples')\n#pl.legend(loc=0)\n#pl.title('OT matrix with samples')\n\n\n#%% sinkhorn\n\n# reg term\nlambd=5e-3\n\nGs=ot.sinkhorn(a,b,M,lambd)\n\n#pl.figure(5)\n#pl.imshow(Gs,interpolation='nearest')\n#pl.title('OT matrix sinkhorn')\n#\n#pl.figure(6)\n#ot.plot.plot2D_samples_mat(xs,xt,Gs,color=[.5,.5,1])\n#pl.plot(xs[:,0],xs[:,1],'+b',label='Source samples')\n#pl.plot(xt[:,0],xt[:,1],'xr',label='Target samples')\n#pl.legend(loc=0)\n#pl.title('OT matrix Sinkhorn with samples')\n#" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 2", - "name": "python2", - "language": "python" - }, - "language_info": { - "mimetype": "text/x-python", - "nbconvert_exporter": "python", - "name": "python", - "file_extension": ".py", - "version": "2.7.12", - "pygments_lexer": "ipython2", - "codemirror_mode": { - "version": 2, - "name": "ipython" - } - } - } -} \ No newline at end of file diff --git a/docs/source/auto_examples/demo_OT_2D_sampleslarge.py b/docs/source/auto_examples/demo_OT_2D_sampleslarge.py deleted file mode 100644 index ee3e8f7..0000000 --- a/docs/source/auto_examples/demo_OT_2D_sampleslarge.py +++ /dev/null @@ -1,78 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Demo for 2D Optimal transport between empirical distributions - -@author: rflamary -""" - -import numpy as np -import matplotlib.pylab as pl -import ot - -#%% parameters and data generation - -n=5000 # nb samples - -mu_s=np.array([0,0]) -cov_s=np.array([[1,0],[0,1]]) - -mu_t=np.array([4,4]) -cov_t=np.array([[1,-.8],[-.8,1]]) - -xs=ot.datasets.get_2D_samples_gauss(n,mu_s,cov_s) -xt=ot.datasets.get_2D_samples_gauss(n,mu_t,cov_t) - -a,b = ot.unif(n),ot.unif(n) # uniform distribution on samples - -# loss matrix -M=ot.dist(xs,xt) -M/=M.max() - -#%% plot samples - -#pl.figure(1) -#pl.plot(xs[:,0],xs[:,1],'+b',label='Source samples') -#pl.plot(xt[:,0],xt[:,1],'xr',label='Target samples') -#pl.legend(loc=0) -#pl.title('Source and traget distributions') -# -#pl.figure(2) -#pl.imshow(M,interpolation='nearest') -#pl.title('Cost matrix M') -# - -#%% EMD - -G0=ot.emd(a,b,M) - -#pl.figure(3) -#pl.imshow(G0,interpolation='nearest') -#pl.title('OT matrix G0') -# -#pl.figure(4) -#ot.plot.plot2D_samples_mat(xs,xt,G0,c=[.5,.5,1]) -#pl.plot(xs[:,0],xs[:,1],'+b',label='Source samples') -#pl.plot(xt[:,0],xt[:,1],'xr',label='Target samples') -#pl.legend(loc=0) -#pl.title('OT matrix with samples') - - -#%% sinkhorn - -# reg term -lambd=5e-3 - -Gs=ot.sinkhorn(a,b,M,lambd) - -#pl.figure(5) -#pl.imshow(Gs,interpolation='nearest') -#pl.title('OT matrix sinkhorn') -# -#pl.figure(6) -#ot.plot.plot2D_samples_mat(xs,xt,Gs,color=[.5,.5,1]) -#pl.plot(xs[:,0],xs[:,1],'+b',label='Source samples') -#pl.plot(xt[:,0],xt[:,1],'xr',label='Target samples') -#pl.legend(loc=0) -#pl.title('OT matrix Sinkhorn with samples') -# - diff --git a/docs/source/auto_examples/demo_OT_2D_sampleslarge.rst b/docs/source/auto_examples/demo_OT_2D_sampleslarge.rst deleted file mode 100644 index f5dbb0d..0000000 --- a/docs/source/auto_examples/demo_OT_2D_sampleslarge.rst +++ /dev/null @@ -1,106 +0,0 @@ - - -.. _sphx_glr_auto_examples_demo_OT_2D_sampleslarge.py: - - -Demo for 2D Optimal transport between empirical distributions - -@author: rflamary - - - -.. code-block:: python - - - import numpy as np - import matplotlib.pylab as pl - import ot - - #%% parameters and data generation - - n=5000 # nb samples - - mu_s=np.array([0,0]) - cov_s=np.array([[1,0],[0,1]]) - - mu_t=np.array([4,4]) - cov_t=np.array([[1,-.8],[-.8,1]]) - - xs=ot.datasets.get_2D_samples_gauss(n,mu_s,cov_s) - xt=ot.datasets.get_2D_samples_gauss(n,mu_t,cov_t) - - a,b = ot.unif(n),ot.unif(n) # uniform distribution on samples - - # loss matrix - M=ot.dist(xs,xt) - M/=M.max() - - #%% plot samples - - #pl.figure(1) - #pl.plot(xs[:,0],xs[:,1],'+b',label='Source samples') - #pl.plot(xt[:,0],xt[:,1],'xr',label='Target samples') - #pl.legend(loc=0) - #pl.title('Source and traget distributions') - # - #pl.figure(2) - #pl.imshow(M,interpolation='nearest') - #pl.title('Cost matrix M') - # - - #%% EMD - - G0=ot.emd(a,b,M) - - #pl.figure(3) - #pl.imshow(G0,interpolation='nearest') - #pl.title('OT matrix G0') - # - #pl.figure(4) - #ot.plot.plot2D_samples_mat(xs,xt,G0,c=[.5,.5,1]) - #pl.plot(xs[:,0],xs[:,1],'+b',label='Source samples') - #pl.plot(xt[:,0],xt[:,1],'xr',label='Target samples') - #pl.legend(loc=0) - #pl.title('OT matrix with samples') - - - #%% sinkhorn - - # reg term - lambd=5e-3 - - Gs=ot.sinkhorn(a,b,M,lambd) - - #pl.figure(5) - #pl.imshow(Gs,interpolation='nearest') - #pl.title('OT matrix sinkhorn') - # - #pl.figure(6) - #ot.plot.plot2D_samples_mat(xs,xt,Gs,color=[.5,.5,1]) - #pl.plot(xs[:,0],xs[:,1],'+b',label='Source samples') - #pl.plot(xt[:,0],xt[:,1],'xr',label='Target samples') - #pl.legend(loc=0) - #pl.title('OT matrix Sinkhorn with samples') - # - - -**Total running time of the script:** ( 0 minutes 0.000 seconds) - - - -.. container:: sphx-glr-footer - - - .. container:: sphx-glr-download - - :download:`Download Python source code: demo_OT_2D_sampleslarge.py ` - - - - .. container:: sphx-glr-download - - :download:`Download Jupyter notebook: demo_OT_2D_sampleslarge.ipynb ` - -.. rst-class:: sphx-glr-signature - - `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_001.png b/docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_001.png deleted file mode 100644 index 7de2b45..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_001.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_002.png b/docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_002.png deleted file mode 100644 index dc34efd..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_002.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_003.png b/docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_003.png deleted file mode 100644 index fbd72d5..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_003.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_004.png b/docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_004.png deleted file mode 100644 index 227812d..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_2D_004.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_classes_001.png b/docs/source/auto_examples/images/sphx_glr_plot_OTDA_classes_001.png deleted file mode 100644 index 2bf4015..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_classes_001.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_classes_004.png b/docs/source/auto_examples/images/sphx_glr_plot_OTDA_classes_004.png deleted file mode 100644 index c1fbf57..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_classes_004.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_color_images_001.png b/docs/source/auto_examples/images/sphx_glr_plot_OTDA_color_images_001.png deleted file mode 100644 index 36bc769..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_color_images_001.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_color_images_002.png b/docs/source/auto_examples/images/sphx_glr_plot_OTDA_color_images_002.png deleted file mode 100644 index 307e384..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_color_images_002.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_001.png b/docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_001.png deleted file mode 100644 index 8c700ee..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_001.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_002.png b/docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_002.png deleted file mode 100644 index 792b404..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_002.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_color_images_001.png b/docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_color_images_001.png deleted file mode 100644 index 36bc769..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_color_images_001.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_color_images_002.png b/docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_color_images_002.png deleted file mode 100644 index 008bf15..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OTDA_mapping_color_images_002.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_1D_003.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_1D_003.png deleted file mode 100644 index a75e649..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_1D_003.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_1D_004.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_1D_004.png deleted file mode 100644 index 96b42cd..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_1D_004.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_001.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_001.png index e675cd8..172d736 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_002.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_002.png index 8c29b7b..3043a72 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_002.png and b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_002.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_003.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_003.png deleted file mode 100644 index 1308674..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_003.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_004.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_004.png deleted file mode 100644 index 95d947e..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_004.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_005.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_005.png index 82ab78c..5565d75 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_005.png and b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_005.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_006.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_006.png index f1d2bfe..06d1020 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_006.png and b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_006.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_001.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_001.png index 22dba2b..6a21f35 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_002.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_002.png index 5dbf96b..79e4710 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_002.png and b/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_002.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_003.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_003.png index e1e9ba8..4860d96 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_005.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_005.png index 79e4710..4860d96 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_005.png and b/docs/source/auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_005.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_WDA_001.png b/docs/source/auto_examples/images/sphx_glr_plot_WDA_001.png index 41ec230..a9fff75 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_WDA_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_WDA_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_WDA_002.png b/docs/source/auto_examples/images/sphx_glr_plot_WDA_002.png deleted file mode 100644 index 95ee7ca..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_WDA_002.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_barycenter_1D_003.png b/docs/source/auto_examples/images/sphx_glr_plot_barycenter_1D_003.png index eac9230..3b23af5 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_barycenter_1D_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_barycenter_1D_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_compute_emd_002.png b/docs/source/auto_examples/images/sphx_glr_plot_compute_emd_002.png deleted file mode 100644 index 7c06255..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_compute_emd_002.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_optim_OTreg_005.png b/docs/source/auto_examples/images/sphx_glr_plot_optim_OTreg_005.png deleted file mode 100644 index 8a4882a..0000000 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_optim_OTreg_005.png and /dev/null differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png index 45a823d..a28f245 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_003.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_003.png index 2798f3b..4d0b12d 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_001.png index 95f882a..2d851c7 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_003.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_003.png index aa1a5d3..a1d99ab 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_005.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_005.png index b43c0cb..f76619b 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_005.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_005.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_001.png index bc583a8..9e78aed 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_003.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_003.png index 7d85e76..d37359b 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_006.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_006.png index fba820a..c71284a 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_006.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_006.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_001.png index 03a3130..d2ee139 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_003.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_003.png index 9c9be23..fa1ab81 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_001.png index 33134fc..1182082 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_003.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_003.png index 42197e3..cc2e4cd 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_004.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_004.png index ebf268b..7a68343 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_004.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_004.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_2D_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_2D_thumb.png deleted file mode 100644 index d15269d..0000000 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_2D_thumb.png and /dev/null differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_classes_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_classes_thumb.png deleted file mode 100644 index 5863d02..0000000 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_classes_thumb.png and /dev/null differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_color_images_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_color_images_thumb.png deleted file mode 100644 index 5bb43c4..0000000 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_color_images_thumb.png and /dev/null differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_mapping_color_images_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_mapping_color_images_thumb.png deleted file mode 100644 index 5bb43c4..0000000 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_mapping_color_images_thumb.png and /dev/null differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_mapping_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_mapping_thumb.png deleted file mode 100644 index c3d9a65..0000000 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OTDA_mapping_thumb.png and /dev/null differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_1D_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_1D_thumb.png index 63ff40c..a3b7039 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_1D_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_1D_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_2D_samples_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_2D_samples_thumb.png index 48e1449..1f42900 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_2D_samples_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_2D_samples_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_L1_vs_L2_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_L1_vs_L2_thumb.png index 9deebf0..95588f5 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_L1_vs_L2_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_L1_vs_L2_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_conv_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_conv_thumb.png deleted file mode 100644 index 3015582..0000000 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_conv_thumb.png and /dev/null differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_WDA_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_WDA_thumb.png index 4b409a0..8db2b9a 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_WDA_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_WDA_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_barycenter_1D_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_barycenter_1D_thumb.png index 5c17671..d8cdccb 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_barycenter_1D_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_barycenter_1D_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_compute_emd_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_compute_emd_thumb.png index 68cbdf7..898cd72 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_compute_emd_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_compute_emd_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_optim_OTreg_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_optim_OTreg_thumb.png index 2a72060..cbc8e0f 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_optim_OTreg_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_optim_OTreg_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png index 3dfc6ca..a2571a5 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_color_images_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_color_images_thumb.png index a919055..16b7572 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_color_images_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_color_images_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png index d9d673c..6c8f37f 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_colors_images_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_colors_images_thumb.png index f7fd217..9666955 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_colors_images_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_colors_images_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png index 4ab5023..a042411 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_test_OT_2D_samples_stabilized_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_test_OT_2D_samples_stabilized_thumb.png deleted file mode 100644 index cbc8e0f..0000000 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_test_OT_2D_samples_stabilized_thumb.png and /dev/null differ diff --git a/docs/source/auto_examples/index.rst b/docs/source/auto_examples/index.rst index b932907..ebcca85 100644 --- a/docs/source/auto_examples/index.rst +++ b/docs/source/auto_examples/index.rst @@ -1,9 +1,15 @@ +:orphan: + POT Examples ============ +This is a gallery of all the POT example files. + + + .. raw:: html -
+
.. only:: html @@ -23,7 +29,7 @@ POT Examples .. raw:: html -
+
.. only:: html @@ -43,7 +49,7 @@ POT Examples .. raw:: html -
+
.. only:: html @@ -63,7 +69,7 @@ POT Examples .. raw:: html -
+
.. only:: html @@ -83,7 +89,7 @@ POT Examples .. raw:: html -
+
.. only:: html @@ -123,7 +129,7 @@ POT Examples .. raw:: html -
+
.. only:: html @@ -143,13 +149,13 @@ POT Examples .. raw:: html -
+
.. only:: html - .. figure:: /auto_examples/images/thumb/sphx_glr_plot_OT_L1_vs_L2_thumb.png + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_otda_mapping_colors_images_thumb.png - :ref:`sphx_glr_auto_examples_plot_OT_L1_vs_L2.py` + :ref:`sphx_glr_auto_examples_plot_otda_mapping_colors_images.py` .. raw:: html @@ -159,17 +165,17 @@ POT Examples .. toctree:: :hidden: - /auto_examples/plot_OT_L1_vs_L2 + /auto_examples/plot_otda_mapping_colors_images .. raw:: html -
+
.. only:: html - .. figure:: /auto_examples/images/thumb/sphx_glr_plot_otda_mapping_colors_images_thumb.png + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png - :ref:`sphx_glr_auto_examples_plot_otda_mapping_colors_images.py` + :ref:`sphx_glr_auto_examples_plot_otda_mapping.py` .. raw:: html @@ -179,17 +185,17 @@ POT Examples .. toctree:: :hidden: - /auto_examples/plot_otda_mapping_colors_images + /auto_examples/plot_otda_mapping .. raw:: html -
+
.. only:: html - .. figure:: /auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png - :ref:`sphx_glr_auto_examples_plot_otda_mapping.py` + :ref:`sphx_glr_auto_examples_plot_otda_classes.py` .. raw:: html @@ -199,17 +205,17 @@ POT Examples .. toctree:: :hidden: - /auto_examples/plot_otda_mapping + /auto_examples/plot_otda_classes .. raw:: html -
+
.. only:: html - .. figure:: /auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png - :ref:`sphx_glr_auto_examples_plot_otda_classes.py` + :ref:`sphx_glr_auto_examples_plot_otda_d2.py` .. raw:: html @@ -219,17 +225,17 @@ POT Examples .. toctree:: :hidden: - /auto_examples/plot_otda_classes + /auto_examples/plot_otda_d2 .. raw:: html -
+
.. only:: html - .. figure:: /auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_OT_L1_vs_L2_thumb.png - :ref:`sphx_glr_auto_examples_plot_otda_d2.py` + :ref:`sphx_glr_auto_examples_plot_OT_L1_vs_L2.py` .. raw:: html @@ -239,7 +245,7 @@ POT Examples .. toctree:: :hidden: - /auto_examples/plot_otda_d2 + /auto_examples/plot_OT_L1_vs_L2 .. raw:: html
@@ -251,14 +257,14 @@ POT Examples .. container:: sphx-glr-download - :download:`Download all examples in Python source code: auto_examples_python.zip ` + :download:`Download all examples in Python source code: auto_examples_python.zip ` .. container:: sphx-glr-download - :download:`Download all examples in Jupyter notebooks: auto_examples_jupyter.zip ` + :download:`Download all examples in Jupyter notebooks: auto_examples_jupyter.zip ` .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_OTDA_2D.ipynb b/docs/source/auto_examples/plot_OTDA_2D.ipynb deleted file mode 100644 index 2ffb256..0000000 --- a/docs/source/auto_examples/plot_OTDA_2D.ipynb +++ /dev/null @@ -1,54 +0,0 @@ -{ - "nbformat_minor": 0, - "nbformat": 4, - "cells": [ - { - "execution_count": null, - "cell_type": "code", - "source": [ - "%matplotlib inline" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - }, - { - "source": [ - "\n# OT for empirical distributions\n\n\n\n" - ], - "cell_type": "markdown", - "metadata": {} - }, - { - "execution_count": null, - "cell_type": "code", - "source": [ - "import numpy as np\nimport matplotlib.pylab as pl\nimport ot\n\n\n\n#%% parameters\n\nn=150 # nb bins\n\nxs,ys=ot.datasets.get_data_classif('3gauss',n)\nxt,yt=ot.datasets.get_data_classif('3gauss2',n)\n\na,b = ot.unif(n),ot.unif(n)\n# loss matrix\nM=ot.dist(xs,xt)\n#M/=M.max()\n\n#%% plot samples\n\npl.figure(1)\n\npl.subplot(2,2,1)\npl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples')\npl.legend(loc=0)\npl.title('Source distributions')\n\npl.subplot(2,2,2)\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples')\npl.legend(loc=0)\npl.title('target distributions')\n\npl.figure(2)\npl.imshow(M,interpolation='nearest')\npl.title('Cost matrix M')\n\n\n#%% OT estimation\n\n# EMD\nG0=ot.emd(a,b,M)\n\n# sinkhorn\nlambd=1e-1\nGs=ot.sinkhorn(a,b,M,lambd)\n\n\n# Group lasso regularization\nreg=1e-1\neta=1e0\nGg=ot.da.sinkhorn_lpl1_mm(a,ys.astype(np.int),b,M,reg,eta)\n\n\n#%% visu matrices\n\npl.figure(3)\n\npl.subplot(2,3,1)\npl.imshow(G0,interpolation='nearest')\npl.title('OT matrix ')\n\npl.subplot(2,3,2)\npl.imshow(Gs,interpolation='nearest')\npl.title('OT matrix Sinkhorn')\n\npl.subplot(2,3,3)\npl.imshow(Gg,interpolation='nearest')\npl.title('OT matrix Group lasso')\n\npl.subplot(2,3,4)\not.plot.plot2D_samples_mat(xs,xt,G0,c=[.5,.5,1])\npl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples')\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples')\n\n\npl.subplot(2,3,5)\not.plot.plot2D_samples_mat(xs,xt,Gs,c=[.5,.5,1])\npl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples')\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples')\n\npl.subplot(2,3,6)\not.plot.plot2D_samples_mat(xs,xt,Gg,c=[.5,.5,1])\npl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples')\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples')\n\n#%% sample interpolation\n\nxst0=n*G0.dot(xt)\nxsts=n*Gs.dot(xt)\nxstg=n*Gg.dot(xt)\n\npl.figure(4)\npl.subplot(2,3,1)\n\n\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.5)\npl.scatter(xst0[:,0],xst0[:,1],c=ys,marker='+',label='Transp samples',s=30)\npl.title('Interp samples')\npl.legend(loc=0)\n\npl.subplot(2,3,2)\n\n\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.5)\npl.scatter(xsts[:,0],xsts[:,1],c=ys,marker='+',label='Transp samples',s=30)\npl.title('Interp samples Sinkhorn')\n\npl.subplot(2,3,3)\n\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.5)\npl.scatter(xstg[:,0],xstg[:,1],c=ys,marker='+',label='Transp samples',s=30)\npl.title('Interp samples Grouplasso')" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 2", - "name": "python2", - "language": "python" - }, - "language_info": { - "mimetype": "text/x-python", - "nbconvert_exporter": "python", - "name": "python", - "file_extension": ".py", - "version": "2.7.12", - "pygments_lexer": "ipython2", - "codemirror_mode": { - "version": 2, - "name": "ipython" - } - } - } -} \ No newline at end of file diff --git a/docs/source/auto_examples/plot_OTDA_2D.py b/docs/source/auto_examples/plot_OTDA_2D.py deleted file mode 100644 index a1fb804..0000000 --- a/docs/source/auto_examples/plot_OTDA_2D.py +++ /dev/null @@ -1,120 +0,0 @@ -# -*- coding: utf-8 -*- -""" -============================== -OT for empirical distributions -============================== - -""" - -import numpy as np -import matplotlib.pylab as pl -import ot - - - -#%% parameters - -n=150 # nb bins - -xs,ys=ot.datasets.get_data_classif('3gauss',n) -xt,yt=ot.datasets.get_data_classif('3gauss2',n) - -a,b = ot.unif(n),ot.unif(n) -# loss matrix -M=ot.dist(xs,xt) -#M/=M.max() - -#%% plot samples - -pl.figure(1) - -pl.subplot(2,2,1) -pl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples') -pl.legend(loc=0) -pl.title('Source distributions') - -pl.subplot(2,2,2) -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples') -pl.legend(loc=0) -pl.title('target distributions') - -pl.figure(2) -pl.imshow(M,interpolation='nearest') -pl.title('Cost matrix M') - - -#%% OT estimation - -# EMD -G0=ot.emd(a,b,M) - -# sinkhorn -lambd=1e-1 -Gs=ot.sinkhorn(a,b,M,lambd) - - -# Group lasso regularization -reg=1e-1 -eta=1e0 -Gg=ot.da.sinkhorn_lpl1_mm(a,ys.astype(np.int),b,M,reg,eta) - - -#%% visu matrices - -pl.figure(3) - -pl.subplot(2,3,1) -pl.imshow(G0,interpolation='nearest') -pl.title('OT matrix ') - -pl.subplot(2,3,2) -pl.imshow(Gs,interpolation='nearest') -pl.title('OT matrix Sinkhorn') - -pl.subplot(2,3,3) -pl.imshow(Gg,interpolation='nearest') -pl.title('OT matrix Group lasso') - -pl.subplot(2,3,4) -ot.plot.plot2D_samples_mat(xs,xt,G0,c=[.5,.5,1]) -pl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples') -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples') - - -pl.subplot(2,3,5) -ot.plot.plot2D_samples_mat(xs,xt,Gs,c=[.5,.5,1]) -pl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples') -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples') - -pl.subplot(2,3,6) -ot.plot.plot2D_samples_mat(xs,xt,Gg,c=[.5,.5,1]) -pl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples') -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples') - -#%% sample interpolation - -xst0=n*G0.dot(xt) -xsts=n*Gs.dot(xt) -xstg=n*Gg.dot(xt) - -pl.figure(4) -pl.subplot(2,3,1) - - -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.5) -pl.scatter(xst0[:,0],xst0[:,1],c=ys,marker='+',label='Transp samples',s=30) -pl.title('Interp samples') -pl.legend(loc=0) - -pl.subplot(2,3,2) - - -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.5) -pl.scatter(xsts[:,0],xsts[:,1],c=ys,marker='+',label='Transp samples',s=30) -pl.title('Interp samples Sinkhorn') - -pl.subplot(2,3,3) - -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.5) -pl.scatter(xstg[:,0],xstg[:,1],c=ys,marker='+',label='Transp samples',s=30) -pl.title('Interp samples Grouplasso') \ No newline at end of file diff --git a/docs/source/auto_examples/plot_OTDA_2D.rst b/docs/source/auto_examples/plot_OTDA_2D.rst deleted file mode 100644 index b535bb0..0000000 --- a/docs/source/auto_examples/plot_OTDA_2D.rst +++ /dev/null @@ -1,175 +0,0 @@ - - -.. _sphx_glr_auto_examples_plot_OTDA_2D.py: - - -============================== -OT for empirical distributions -============================== - - - - - -.. rst-class:: sphx-glr-horizontal - - - * - - .. image:: /auto_examples/images/sphx_glr_plot_OTDA_2D_001.png - :scale: 47 - - * - - .. image:: /auto_examples/images/sphx_glr_plot_OTDA_2D_002.png - :scale: 47 - - * - - .. image:: /auto_examples/images/sphx_glr_plot_OTDA_2D_003.png - :scale: 47 - - * - - .. image:: /auto_examples/images/sphx_glr_plot_OTDA_2D_004.png - :scale: 47 - - - - - -.. code-block:: python - - - import numpy as np - import matplotlib.pylab as pl - import ot - - - - #%% parameters - - n=150 # nb bins - - xs,ys=ot.datasets.get_data_classif('3gauss',n) - xt,yt=ot.datasets.get_data_classif('3gauss2',n) - - a,b = ot.unif(n),ot.unif(n) - # loss matrix - M=ot.dist(xs,xt) - #M/=M.max() - - #%% plot samples - - pl.figure(1) - - pl.subplot(2,2,1) - pl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples') - pl.legend(loc=0) - pl.title('Source distributions') - - pl.subplot(2,2,2) - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples') - pl.legend(loc=0) - pl.title('target distributions') - - pl.figure(2) - pl.imshow(M,interpolation='nearest') - pl.title('Cost matrix M') - - - #%% OT estimation - - # EMD - G0=ot.emd(a,b,M) - - # sinkhorn - lambd=1e-1 - Gs=ot.sinkhorn(a,b,M,lambd) - - - # Group lasso regularization - reg=1e-1 - eta=1e0 - Gg=ot.da.sinkhorn_lpl1_mm(a,ys.astype(np.int),b,M,reg,eta) - - - #%% visu matrices - - pl.figure(3) - - pl.subplot(2,3,1) - pl.imshow(G0,interpolation='nearest') - pl.title('OT matrix ') - - pl.subplot(2,3,2) - pl.imshow(Gs,interpolation='nearest') - pl.title('OT matrix Sinkhorn') - - pl.subplot(2,3,3) - pl.imshow(Gg,interpolation='nearest') - pl.title('OT matrix Group lasso') - - pl.subplot(2,3,4) - ot.plot.plot2D_samples_mat(xs,xt,G0,c=[.5,.5,1]) - pl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples') - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples') - - - pl.subplot(2,3,5) - ot.plot.plot2D_samples_mat(xs,xt,Gs,c=[.5,.5,1]) - pl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples') - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples') - - pl.subplot(2,3,6) - ot.plot.plot2D_samples_mat(xs,xt,Gg,c=[.5,.5,1]) - pl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples') - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples') - - #%% sample interpolation - - xst0=n*G0.dot(xt) - xsts=n*Gs.dot(xt) - xstg=n*Gg.dot(xt) - - pl.figure(4) - pl.subplot(2,3,1) - - - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.5) - pl.scatter(xst0[:,0],xst0[:,1],c=ys,marker='+',label='Transp samples',s=30) - pl.title('Interp samples') - pl.legend(loc=0) - - pl.subplot(2,3,2) - - - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.5) - pl.scatter(xsts[:,0],xsts[:,1],c=ys,marker='+',label='Transp samples',s=30) - pl.title('Interp samples Sinkhorn') - - pl.subplot(2,3,3) - - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.5) - pl.scatter(xstg[:,0],xstg[:,1],c=ys,marker='+',label='Transp samples',s=30) - pl.title('Interp samples Grouplasso') -**Total running time of the script:** ( 0 minutes 17.372 seconds) - - - -.. container:: sphx-glr-footer - - - .. container:: sphx-glr-download - - :download:`Download Python source code: plot_OTDA_2D.py ` - - - - .. container:: sphx-glr-download - - :download:`Download Jupyter notebook: plot_OTDA_2D.ipynb ` - -.. rst-class:: sphx-glr-signature - - `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_OTDA_classes.ipynb b/docs/source/auto_examples/plot_OTDA_classes.ipynb deleted file mode 100644 index d9fcb87..0000000 --- a/docs/source/auto_examples/plot_OTDA_classes.ipynb +++ /dev/null @@ -1,54 +0,0 @@ -{ - "nbformat_minor": 0, - "nbformat": 4, - "cells": [ - { - "execution_count": null, - "cell_type": "code", - "source": [ - "%matplotlib inline" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - }, - { - "source": [ - "\n# OT for domain adaptation\n\n\n\n" - ], - "cell_type": "markdown", - "metadata": {} - }, - { - "execution_count": null, - "cell_type": "code", - "source": [ - "import matplotlib.pylab as pl\nimport ot\n\n\n\n\n#%% parameters\n\nn=150 # nb samples in source and target datasets\n\nxs,ys=ot.datasets.get_data_classif('3gauss',n)\nxt,yt=ot.datasets.get_data_classif('3gauss2',n)\n\n\n\n\n#%% plot samples\n\npl.figure(1)\n\npl.subplot(2,2,1)\npl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples')\npl.legend(loc=0)\npl.title('Source distributions')\n\npl.subplot(2,2,2)\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples')\npl.legend(loc=0)\npl.title('target distributions')\n\n\n#%% OT estimation\n\n# LP problem\nda_emd=ot.da.OTDA() # init class\nda_emd.fit(xs,xt) # fit distributions\nxst0=da_emd.interp() # interpolation of source samples\n\n\n# sinkhorn regularization\nlambd=1e-1\nda_entrop=ot.da.OTDA_sinkhorn()\nda_entrop.fit(xs,xt,reg=lambd)\nxsts=da_entrop.interp()\n\n# non-convex Group lasso regularization\nreg=1e-1\neta=1e0\nda_lpl1=ot.da.OTDA_lpl1()\nda_lpl1.fit(xs,ys,xt,reg=reg,eta=eta)\nxstg=da_lpl1.interp()\n\n\n# True Group lasso regularization\nreg=1e-1\neta=2e0\nda_l1l2=ot.da.OTDA_l1l2()\nda_l1l2.fit(xs,ys,xt,reg=reg,eta=eta,numItermax=20,verbose=True)\nxstgl=da_l1l2.interp()\n\n\n#%% plot interpolated source samples\npl.figure(4,(15,8))\n\nparam_img={'interpolation':'nearest','cmap':'jet'}\n\npl.subplot(2,4,1)\npl.imshow(da_emd.G,**param_img)\npl.title('OT matrix')\n\n\npl.subplot(2,4,2)\npl.imshow(da_entrop.G,**param_img)\npl.title('OT matrix sinkhorn')\n\npl.subplot(2,4,3)\npl.imshow(da_lpl1.G,**param_img)\npl.title('OT matrix non-convex Group Lasso')\n\npl.subplot(2,4,4)\npl.imshow(da_l1l2.G,**param_img)\npl.title('OT matrix Group Lasso')\n\n\npl.subplot(2,4,5)\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.3)\npl.scatter(xst0[:,0],xst0[:,1],c=ys,marker='+',label='Transp samples',s=30)\npl.title('Interp samples')\npl.legend(loc=0)\n\npl.subplot(2,4,6)\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.3)\npl.scatter(xsts[:,0],xsts[:,1],c=ys,marker='+',label='Transp samples',s=30)\npl.title('Interp samples Sinkhorn')\n\npl.subplot(2,4,7)\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.3)\npl.scatter(xstg[:,0],xstg[:,1],c=ys,marker='+',label='Transp samples',s=30)\npl.title('Interp samples non-convex Group Lasso')\n\npl.subplot(2,4,8)\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.3)\npl.scatter(xstgl[:,0],xstgl[:,1],c=ys,marker='+',label='Transp samples',s=30)\npl.title('Interp samples Group Lasso')" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 2", - "name": "python2", - "language": "python" - }, - "language_info": { - "mimetype": "text/x-python", - "nbconvert_exporter": "python", - "name": "python", - "file_extension": ".py", - "version": "2.7.12", - "pygments_lexer": "ipython2", - "codemirror_mode": { - "version": 2, - "name": "ipython" - } - } - } -} \ No newline at end of file diff --git a/docs/source/auto_examples/plot_OTDA_classes.py b/docs/source/auto_examples/plot_OTDA_classes.py deleted file mode 100644 index 089b45b..0000000 --- a/docs/source/auto_examples/plot_OTDA_classes.py +++ /dev/null @@ -1,112 +0,0 @@ -# -*- coding: utf-8 -*- -""" -======================== -OT for domain adaptation -======================== - -""" - -import matplotlib.pylab as pl -import ot - - - - -#%% parameters - -n=150 # nb samples in source and target datasets - -xs,ys=ot.datasets.get_data_classif('3gauss',n) -xt,yt=ot.datasets.get_data_classif('3gauss2',n) - - - - -#%% plot samples - -pl.figure(1) - -pl.subplot(2,2,1) -pl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples') -pl.legend(loc=0) -pl.title('Source distributions') - -pl.subplot(2,2,2) -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples') -pl.legend(loc=0) -pl.title('target distributions') - - -#%% OT estimation - -# LP problem -da_emd=ot.da.OTDA() # init class -da_emd.fit(xs,xt) # fit distributions -xst0=da_emd.interp() # interpolation of source samples - - -# sinkhorn regularization -lambd=1e-1 -da_entrop=ot.da.OTDA_sinkhorn() -da_entrop.fit(xs,xt,reg=lambd) -xsts=da_entrop.interp() - -# non-convex Group lasso regularization -reg=1e-1 -eta=1e0 -da_lpl1=ot.da.OTDA_lpl1() -da_lpl1.fit(xs,ys,xt,reg=reg,eta=eta) -xstg=da_lpl1.interp() - - -# True Group lasso regularization -reg=1e-1 -eta=2e0 -da_l1l2=ot.da.OTDA_l1l2() -da_l1l2.fit(xs,ys,xt,reg=reg,eta=eta,numItermax=20,verbose=True) -xstgl=da_l1l2.interp() - - -#%% plot interpolated source samples -pl.figure(4,(15,8)) - -param_img={'interpolation':'nearest','cmap':'jet'} - -pl.subplot(2,4,1) -pl.imshow(da_emd.G,**param_img) -pl.title('OT matrix') - - -pl.subplot(2,4,2) -pl.imshow(da_entrop.G,**param_img) -pl.title('OT matrix sinkhorn') - -pl.subplot(2,4,3) -pl.imshow(da_lpl1.G,**param_img) -pl.title('OT matrix non-convex Group Lasso') - -pl.subplot(2,4,4) -pl.imshow(da_l1l2.G,**param_img) -pl.title('OT matrix Group Lasso') - - -pl.subplot(2,4,5) -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.3) -pl.scatter(xst0[:,0],xst0[:,1],c=ys,marker='+',label='Transp samples',s=30) -pl.title('Interp samples') -pl.legend(loc=0) - -pl.subplot(2,4,6) -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.3) -pl.scatter(xsts[:,0],xsts[:,1],c=ys,marker='+',label='Transp samples',s=30) -pl.title('Interp samples Sinkhorn') - -pl.subplot(2,4,7) -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.3) -pl.scatter(xstg[:,0],xstg[:,1],c=ys,marker='+',label='Transp samples',s=30) -pl.title('Interp samples non-convex Group Lasso') - -pl.subplot(2,4,8) -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.3) -pl.scatter(xstgl[:,0],xstgl[:,1],c=ys,marker='+',label='Transp samples',s=30) -pl.title('Interp samples Group Lasso') \ No newline at end of file diff --git a/docs/source/auto_examples/plot_OTDA_classes.rst b/docs/source/auto_examples/plot_OTDA_classes.rst deleted file mode 100644 index 097e9fc..0000000 --- a/docs/source/auto_examples/plot_OTDA_classes.rst +++ /dev/null @@ -1,190 +0,0 @@ - - -.. _sphx_glr_auto_examples_plot_OTDA_classes.py: - - -======================== -OT for domain adaptation -======================== - - - - - -.. rst-class:: sphx-glr-horizontal - - - * - - .. image:: /auto_examples/images/sphx_glr_plot_OTDA_classes_001.png - :scale: 47 - - * - - .. image:: /auto_examples/images/sphx_glr_plot_OTDA_classes_004.png - :scale: 47 - - -.. rst-class:: sphx-glr-script-out - - Out:: - - It. |Loss |Delta loss - -------------------------------- - 0|9.171271e+00|0.000000e+00 - 1|2.133783e+00|-3.298127e+00 - 2|1.895941e+00|-1.254484e-01 - 3|1.844628e+00|-2.781709e-02 - 4|1.824983e+00|-1.076467e-02 - 5|1.815453e+00|-5.249337e-03 - 6|1.808104e+00|-4.064733e-03 - 7|1.803558e+00|-2.520475e-03 - 8|1.801061e+00|-1.386155e-03 - 9|1.799391e+00|-9.279565e-04 - 10|1.797176e+00|-1.232778e-03 - 11|1.795465e+00|-9.529479e-04 - 12|1.795316e+00|-8.322362e-05 - 13|1.794523e+00|-4.418932e-04 - 14|1.794444e+00|-4.390599e-05 - 15|1.794395e+00|-2.710318e-05 - 16|1.793713e+00|-3.804028e-04 - 17|1.793110e+00|-3.359479e-04 - 18|1.792829e+00|-1.569563e-04 - 19|1.792621e+00|-1.159469e-04 - It. |Loss |Delta loss - -------------------------------- - 20|1.791334e+00|-7.187689e-04 - - - - -| - - -.. code-block:: python - - - import matplotlib.pylab as pl - import ot - - - - - #%% parameters - - n=150 # nb samples in source and target datasets - - xs,ys=ot.datasets.get_data_classif('3gauss',n) - xt,yt=ot.datasets.get_data_classif('3gauss2',n) - - - - - #%% plot samples - - pl.figure(1) - - pl.subplot(2,2,1) - pl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples') - pl.legend(loc=0) - pl.title('Source distributions') - - pl.subplot(2,2,2) - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples') - pl.legend(loc=0) - pl.title('target distributions') - - - #%% OT estimation - - # LP problem - da_emd=ot.da.OTDA() # init class - da_emd.fit(xs,xt) # fit distributions - xst0=da_emd.interp() # interpolation of source samples - - - # sinkhorn regularization - lambd=1e-1 - da_entrop=ot.da.OTDA_sinkhorn() - da_entrop.fit(xs,xt,reg=lambd) - xsts=da_entrop.interp() - - # non-convex Group lasso regularization - reg=1e-1 - eta=1e0 - da_lpl1=ot.da.OTDA_lpl1() - da_lpl1.fit(xs,ys,xt,reg=reg,eta=eta) - xstg=da_lpl1.interp() - - - # True Group lasso regularization - reg=1e-1 - eta=2e0 - da_l1l2=ot.da.OTDA_l1l2() - da_l1l2.fit(xs,ys,xt,reg=reg,eta=eta,numItermax=20,verbose=True) - xstgl=da_l1l2.interp() - - - #%% plot interpolated source samples - pl.figure(4,(15,8)) - - param_img={'interpolation':'nearest','cmap':'jet'} - - pl.subplot(2,4,1) - pl.imshow(da_emd.G,**param_img) - pl.title('OT matrix') - - - pl.subplot(2,4,2) - pl.imshow(da_entrop.G,**param_img) - pl.title('OT matrix sinkhorn') - - pl.subplot(2,4,3) - pl.imshow(da_lpl1.G,**param_img) - pl.title('OT matrix non-convex Group Lasso') - - pl.subplot(2,4,4) - pl.imshow(da_l1l2.G,**param_img) - pl.title('OT matrix Group Lasso') - - - pl.subplot(2,4,5) - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.3) - pl.scatter(xst0[:,0],xst0[:,1],c=ys,marker='+',label='Transp samples',s=30) - pl.title('Interp samples') - pl.legend(loc=0) - - pl.subplot(2,4,6) - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.3) - pl.scatter(xsts[:,0],xsts[:,1],c=ys,marker='+',label='Transp samples',s=30) - pl.title('Interp samples Sinkhorn') - - pl.subplot(2,4,7) - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.3) - pl.scatter(xstg[:,0],xstg[:,1],c=ys,marker='+',label='Transp samples',s=30) - pl.title('Interp samples non-convex Group Lasso') - - pl.subplot(2,4,8) - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=0.3) - pl.scatter(xstgl[:,0],xstgl[:,1],c=ys,marker='+',label='Transp samples',s=30) - pl.title('Interp samples Group Lasso') -**Total running time of the script:** ( 0 minutes 2.225 seconds) - - - -.. container:: sphx-glr-footer - - - .. container:: sphx-glr-download - - :download:`Download Python source code: plot_OTDA_classes.py ` - - - - .. container:: sphx-glr-download - - :download:`Download Jupyter notebook: plot_OTDA_classes.ipynb ` - -.. rst-class:: sphx-glr-signature - - `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_OTDA_color_images.ipynb b/docs/source/auto_examples/plot_OTDA_color_images.ipynb deleted file mode 100644 index d174828..0000000 --- a/docs/source/auto_examples/plot_OTDA_color_images.ipynb +++ /dev/null @@ -1,54 +0,0 @@ -{ - "nbformat_minor": 0, - "nbformat": 4, - "cells": [ - { - "execution_count": null, - "cell_type": "code", - "source": [ - "%matplotlib inline" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - }, - { - "source": [ - "\n========================================================\nOT for domain adaptation with image color adaptation [6]\n========================================================\n\n[6] Ferradans, S., Papadakis, N., Peyre, G., & Aujol, J. F. (2014). Regularized discrete optimal transport. SIAM Journal on Imaging Sciences, 7(3), 1853-1882.\n\n" - ], - "cell_type": "markdown", - "metadata": {} - }, - { - "execution_count": null, - "cell_type": "code", - "source": [ - "import numpy as np\nimport scipy.ndimage as spi\nimport matplotlib.pylab as pl\nimport ot\n\n\n#%% Loading images\n\nI1=spi.imread('../data/ocean_day.jpg').astype(np.float64)/256\nI2=spi.imread('../data/ocean_sunset.jpg').astype(np.float64)/256\n\n#%% Plot images\n\npl.figure(1)\n\npl.subplot(1,2,1)\npl.imshow(I1)\npl.title('Image 1')\n\npl.subplot(1,2,2)\npl.imshow(I2)\npl.title('Image 2')\n\npl.show()\n\n#%% Image conversion and dataset generation\n\ndef im2mat(I):\n \"\"\"Converts and image to matrix (one pixel per line)\"\"\"\n return I.reshape((I.shape[0]*I.shape[1],I.shape[2]))\n\ndef mat2im(X,shape):\n \"\"\"Converts back a matrix to an image\"\"\"\n return X.reshape(shape)\n\nX1=im2mat(I1)\nX2=im2mat(I2)\n\n# training samples\nnb=1000\nidx1=np.random.randint(X1.shape[0],size=(nb,))\nidx2=np.random.randint(X2.shape[0],size=(nb,))\n\nxs=X1[idx1,:]\nxt=X2[idx2,:]\n\n#%% Plot image distributions\n\n\npl.figure(2,(10,5))\n\npl.subplot(1,2,1)\npl.scatter(xs[:,0],xs[:,2],c=xs)\npl.axis([0,1,0,1])\npl.xlabel('Red')\npl.ylabel('Blue')\npl.title('Image 1')\n\npl.subplot(1,2,2)\n#pl.imshow(I2)\npl.scatter(xt[:,0],xt[:,2],c=xt)\npl.axis([0,1,0,1])\npl.xlabel('Red')\npl.ylabel('Blue')\npl.title('Image 2')\n\npl.show()\n\n\n\n#%% domain adaptation between images\n\n# LP problem\nda_emd=ot.da.OTDA() # init class\nda_emd.fit(xs,xt) # fit distributions\n\n\n# sinkhorn regularization\nlambd=1e-1\nda_entrop=ot.da.OTDA_sinkhorn()\nda_entrop.fit(xs,xt,reg=lambd)\n\n\n\n#%% prediction between images (using out of sample prediction as in [6])\n\nX1t=da_emd.predict(X1)\nX2t=da_emd.predict(X2,-1)\n\n\nX1te=da_entrop.predict(X1)\nX2te=da_entrop.predict(X2,-1)\n\n\ndef minmax(I):\n return np.minimum(np.maximum(I,0),1)\n\nI1t=minmax(mat2im(X1t,I1.shape))\nI2t=minmax(mat2im(X2t,I2.shape))\n\nI1te=minmax(mat2im(X1te,I1.shape))\nI2te=minmax(mat2im(X2te,I2.shape))\n\n#%% plot all images\n\npl.figure(2,(10,8))\n\npl.subplot(2,3,1)\n\npl.imshow(I1)\npl.title('Image 1')\n\npl.subplot(2,3,2)\npl.imshow(I1t)\npl.title('Image 1 Adapt')\n\n\npl.subplot(2,3,3)\npl.imshow(I1te)\npl.title('Image 1 Adapt (reg)')\n\npl.subplot(2,3,4)\n\npl.imshow(I2)\npl.title('Image 2')\n\npl.subplot(2,3,5)\npl.imshow(I2t)\npl.title('Image 2 Adapt')\n\n\npl.subplot(2,3,6)\npl.imshow(I2te)\npl.title('Image 2 Adapt (reg)')\n\npl.show()" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 2", - "name": "python2", - "language": "python" - }, - "language_info": { - "mimetype": "text/x-python", - "nbconvert_exporter": "python", - "name": "python", - "file_extension": ".py", - "version": "2.7.12", - "pygments_lexer": "ipython2", - "codemirror_mode": { - "version": 2, - "name": "ipython" - } - } - } -} \ No newline at end of file diff --git a/docs/source/auto_examples/plot_OTDA_color_images.py b/docs/source/auto_examples/plot_OTDA_color_images.py deleted file mode 100644 index 68eee44..0000000 --- a/docs/source/auto_examples/plot_OTDA_color_images.py +++ /dev/null @@ -1,145 +0,0 @@ -# -*- coding: utf-8 -*- -""" -======================================================== -OT for domain adaptation with image color adaptation [6] -======================================================== - -[6] Ferradans, S., Papadakis, N., Peyre, G., & Aujol, J. F. (2014). Regularized discrete optimal transport. SIAM Journal on Imaging Sciences, 7(3), 1853-1882. -""" - -import numpy as np -import scipy.ndimage as spi -import matplotlib.pylab as pl -import ot - - -#%% Loading images - -I1=spi.imread('../data/ocean_day.jpg').astype(np.float64)/256 -I2=spi.imread('../data/ocean_sunset.jpg').astype(np.float64)/256 - -#%% Plot images - -pl.figure(1) - -pl.subplot(1,2,1) -pl.imshow(I1) -pl.title('Image 1') - -pl.subplot(1,2,2) -pl.imshow(I2) -pl.title('Image 2') - -pl.show() - -#%% Image conversion and dataset generation - -def im2mat(I): - """Converts and image to matrix (one pixel per line)""" - return I.reshape((I.shape[0]*I.shape[1],I.shape[2])) - -def mat2im(X,shape): - """Converts back a matrix to an image""" - return X.reshape(shape) - -X1=im2mat(I1) -X2=im2mat(I2) - -# training samples -nb=1000 -idx1=np.random.randint(X1.shape[0],size=(nb,)) -idx2=np.random.randint(X2.shape[0],size=(nb,)) - -xs=X1[idx1,:] -xt=X2[idx2,:] - -#%% Plot image distributions - - -pl.figure(2,(10,5)) - -pl.subplot(1,2,1) -pl.scatter(xs[:,0],xs[:,2],c=xs) -pl.axis([0,1,0,1]) -pl.xlabel('Red') -pl.ylabel('Blue') -pl.title('Image 1') - -pl.subplot(1,2,2) -#pl.imshow(I2) -pl.scatter(xt[:,0],xt[:,2],c=xt) -pl.axis([0,1,0,1]) -pl.xlabel('Red') -pl.ylabel('Blue') -pl.title('Image 2') - -pl.show() - - - -#%% domain adaptation between images - -# LP problem -da_emd=ot.da.OTDA() # init class -da_emd.fit(xs,xt) # fit distributions - - -# sinkhorn regularization -lambd=1e-1 -da_entrop=ot.da.OTDA_sinkhorn() -da_entrop.fit(xs,xt,reg=lambd) - - - -#%% prediction between images (using out of sample prediction as in [6]) - -X1t=da_emd.predict(X1) -X2t=da_emd.predict(X2,-1) - - -X1te=da_entrop.predict(X1) -X2te=da_entrop.predict(X2,-1) - - -def minmax(I): - return np.minimum(np.maximum(I,0),1) - -I1t=minmax(mat2im(X1t,I1.shape)) -I2t=minmax(mat2im(X2t,I2.shape)) - -I1te=minmax(mat2im(X1te,I1.shape)) -I2te=minmax(mat2im(X2te,I2.shape)) - -#%% plot all images - -pl.figure(2,(10,8)) - -pl.subplot(2,3,1) - -pl.imshow(I1) -pl.title('Image 1') - -pl.subplot(2,3,2) -pl.imshow(I1t) -pl.title('Image 1 Adapt') - - -pl.subplot(2,3,3) -pl.imshow(I1te) -pl.title('Image 1 Adapt (reg)') - -pl.subplot(2,3,4) - -pl.imshow(I2) -pl.title('Image 2') - -pl.subplot(2,3,5) -pl.imshow(I2t) -pl.title('Image 2 Adapt') - - -pl.subplot(2,3,6) -pl.imshow(I2te) -pl.title('Image 2 Adapt (reg)') - -pl.show() diff --git a/docs/source/auto_examples/plot_OTDA_color_images.rst b/docs/source/auto_examples/plot_OTDA_color_images.rst deleted file mode 100644 index a982a90..0000000 --- a/docs/source/auto_examples/plot_OTDA_color_images.rst +++ /dev/null @@ -1,191 +0,0 @@ - - -.. _sphx_glr_auto_examples_plot_OTDA_color_images.py: - - -======================================================== -OT for domain adaptation with image color adaptation [6] -======================================================== - -[6] Ferradans, S., Papadakis, N., Peyre, G., & Aujol, J. F. (2014). Regularized discrete optimal transport. SIAM Journal on Imaging Sciences, 7(3), 1853-1882. - - - - -.. rst-class:: sphx-glr-horizontal - - - * - - .. image:: /auto_examples/images/sphx_glr_plot_OTDA_color_images_001.png - :scale: 47 - - * - - .. image:: /auto_examples/images/sphx_glr_plot_OTDA_color_images_002.png - :scale: 47 - - - - - -.. code-block:: python - - - import numpy as np - import scipy.ndimage as spi - import matplotlib.pylab as pl - import ot - - - #%% Loading images - - I1=spi.imread('../data/ocean_day.jpg').astype(np.float64)/256 - I2=spi.imread('../data/ocean_sunset.jpg').astype(np.float64)/256 - - #%% Plot images - - pl.figure(1) - - pl.subplot(1,2,1) - pl.imshow(I1) - pl.title('Image 1') - - pl.subplot(1,2,2) - pl.imshow(I2) - pl.title('Image 2') - - pl.show() - - #%% Image conversion and dataset generation - - def im2mat(I): - """Converts and image to matrix (one pixel per line)""" - return I.reshape((I.shape[0]*I.shape[1],I.shape[2])) - - def mat2im(X,shape): - """Converts back a matrix to an image""" - return X.reshape(shape) - - X1=im2mat(I1) - X2=im2mat(I2) - - # training samples - nb=1000 - idx1=np.random.randint(X1.shape[0],size=(nb,)) - idx2=np.random.randint(X2.shape[0],size=(nb,)) - - xs=X1[idx1,:] - xt=X2[idx2,:] - - #%% Plot image distributions - - - pl.figure(2,(10,5)) - - pl.subplot(1,2,1) - pl.scatter(xs[:,0],xs[:,2],c=xs) - pl.axis([0,1,0,1]) - pl.xlabel('Red') - pl.ylabel('Blue') - pl.title('Image 1') - - pl.subplot(1,2,2) - #pl.imshow(I2) - pl.scatter(xt[:,0],xt[:,2],c=xt) - pl.axis([0,1,0,1]) - pl.xlabel('Red') - pl.ylabel('Blue') - pl.title('Image 2') - - pl.show() - - - - #%% domain adaptation between images - - # LP problem - da_emd=ot.da.OTDA() # init class - da_emd.fit(xs,xt) # fit distributions - - - # sinkhorn regularization - lambd=1e-1 - da_entrop=ot.da.OTDA_sinkhorn() - da_entrop.fit(xs,xt,reg=lambd) - - - - #%% prediction between images (using out of sample prediction as in [6]) - - X1t=da_emd.predict(X1) - X2t=da_emd.predict(X2,-1) - - - X1te=da_entrop.predict(X1) - X2te=da_entrop.predict(X2,-1) - - - def minmax(I): - return np.minimum(np.maximum(I,0),1) - - I1t=minmax(mat2im(X1t,I1.shape)) - I2t=minmax(mat2im(X2t,I2.shape)) - - I1te=minmax(mat2im(X1te,I1.shape)) - I2te=minmax(mat2im(X2te,I2.shape)) - - #%% plot all images - - pl.figure(2,(10,8)) - - pl.subplot(2,3,1) - - pl.imshow(I1) - pl.title('Image 1') - - pl.subplot(2,3,2) - pl.imshow(I1t) - pl.title('Image 1 Adapt') - - - pl.subplot(2,3,3) - pl.imshow(I1te) - pl.title('Image 1 Adapt (reg)') - - pl.subplot(2,3,4) - - pl.imshow(I2) - pl.title('Image 2') - - pl.subplot(2,3,5) - pl.imshow(I2t) - pl.title('Image 2 Adapt') - - - pl.subplot(2,3,6) - pl.imshow(I2te) - pl.title('Image 2 Adapt (reg)') - - pl.show() - -**Total running time of the script:** ( 0 minutes 24.815 seconds) - - - -.. container:: sphx-glr-footer - - - .. container:: sphx-glr-download - - :download:`Download Python source code: plot_OTDA_color_images.py ` - - - - .. container:: sphx-glr-download - - :download:`Download Jupyter notebook: plot_OTDA_color_images.ipynb ` - -.. rst-class:: sphx-glr-signature - - `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_OTDA_mapping.ipynb b/docs/source/auto_examples/plot_OTDA_mapping.ipynb deleted file mode 100644 index ec405af..0000000 --- a/docs/source/auto_examples/plot_OTDA_mapping.ipynb +++ /dev/null @@ -1,54 +0,0 @@ -{ - "nbformat_minor": 0, - "nbformat": 4, - "cells": [ - { - "execution_count": null, - "cell_type": "code", - "source": [ - "%matplotlib inline" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - }, - { - "source": [ - "\n===============================================\nOT mapping estimation for domain adaptation [8]\n===============================================\n\n[8] M. Perrot, N. Courty, R. Flamary, A. Habrard, \"Mapping estimation for\n discrete optimal transport\", Neural Information Processing Systems (NIPS), 2016.\n\n" - ], - "cell_type": "markdown", - "metadata": {} - }, - { - "execution_count": null, - "cell_type": "code", - "source": [ - "import numpy as np\nimport matplotlib.pylab as pl\nimport ot\n\n\n\n#%% dataset generation\n\nnp.random.seed(0) # makes example reproducible\n\nn=100 # nb samples in source and target datasets\ntheta=2*np.pi/20\nnz=0.1\nxs,ys=ot.datasets.get_data_classif('gaussrot',n,nz=nz)\nxt,yt=ot.datasets.get_data_classif('gaussrot',n,theta=theta,nz=nz)\n\n# one of the target mode changes its variance (no linear mapping)\nxt[yt==2]*=3\nxt=xt+4\n\n\n#%% plot samples\n\npl.figure(1,(8,5))\npl.clf()\n\npl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples')\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples')\n\npl.legend(loc=0)\npl.title('Source and target distributions')\n\n\n\n#%% OT linear mapping estimation\n\neta=1e-8 # quadratic regularization for regression\nmu=1e0 # weight of the OT linear term\nbias=True # estimate a bias\n\not_mapping=ot.da.OTDA_mapping_linear()\not_mapping.fit(xs,xt,mu=mu,eta=eta,bias=bias,numItermax = 20,verbose=True)\n\nxst=ot_mapping.predict(xs) # use the estimated mapping\nxst0=ot_mapping.interp() # use barycentric mapping\n\n\npl.figure(2,(10,7))\npl.clf()\npl.subplot(2,2,1)\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.3)\npl.scatter(xst0[:,0],xst0[:,1],c=ys,marker='+',label='barycentric mapping')\npl.title(\"barycentric mapping\")\n\npl.subplot(2,2,2)\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.3)\npl.scatter(xst[:,0],xst[:,1],c=ys,marker='+',label='Learned mapping')\npl.title(\"Learned mapping\")\n\n\n\n#%% Kernel mapping estimation\n\neta=1e-5 # quadratic regularization for regression\nmu=1e-1 # weight of the OT linear term\nbias=True # estimate a bias\nsigma=1 # sigma bandwidth fot gaussian kernel\n\n\not_mapping_kernel=ot.da.OTDA_mapping_kernel()\not_mapping_kernel.fit(xs,xt,mu=mu,eta=eta,sigma=sigma,bias=bias,numItermax = 10,verbose=True)\n\nxst_kernel=ot_mapping_kernel.predict(xs) # use the estimated mapping\nxst0_kernel=ot_mapping_kernel.interp() # use barycentric mapping\n\n\n#%% Plotting the mapped samples\n\npl.figure(2,(10,7))\npl.clf()\npl.subplot(2,2,1)\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.2)\npl.scatter(xst0[:,0],xst0[:,1],c=ys,marker='+',label='Mapped source samples')\npl.title(\"Bary. mapping (linear)\")\npl.legend(loc=0)\n\npl.subplot(2,2,2)\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.2)\npl.scatter(xst[:,0],xst[:,1],c=ys,marker='+',label='Learned mapping')\npl.title(\"Estim. mapping (linear)\")\n\npl.subplot(2,2,3)\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.2)\npl.scatter(xst0_kernel[:,0],xst0_kernel[:,1],c=ys,marker='+',label='barycentric mapping')\npl.title(\"Bary. mapping (kernel)\")\n\npl.subplot(2,2,4)\npl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.2)\npl.scatter(xst_kernel[:,0],xst_kernel[:,1],c=ys,marker='+',label='Learned mapping')\npl.title(\"Estim. mapping (kernel)\")" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 2", - "name": "python2", - "language": "python" - }, - "language_info": { - "mimetype": "text/x-python", - "nbconvert_exporter": "python", - "name": "python", - "file_extension": ".py", - "version": "2.7.12", - "pygments_lexer": "ipython2", - "codemirror_mode": { - "version": 2, - "name": "ipython" - } - } - } -} \ No newline at end of file diff --git a/docs/source/auto_examples/plot_OTDA_mapping.py b/docs/source/auto_examples/plot_OTDA_mapping.py deleted file mode 100644 index 78b57e7..0000000 --- a/docs/source/auto_examples/plot_OTDA_mapping.py +++ /dev/null @@ -1,110 +0,0 @@ -# -*- coding: utf-8 -*- -""" -=============================================== -OT mapping estimation for domain adaptation [8] -=============================================== - -[8] M. Perrot, N. Courty, R. Flamary, A. Habrard, "Mapping estimation for - discrete optimal transport", Neural Information Processing Systems (NIPS), 2016. -""" - -import numpy as np -import matplotlib.pylab as pl -import ot - - - -#%% dataset generation - -np.random.seed(0) # makes example reproducible - -n=100 # nb samples in source and target datasets -theta=2*np.pi/20 -nz=0.1 -xs,ys=ot.datasets.get_data_classif('gaussrot',n,nz=nz) -xt,yt=ot.datasets.get_data_classif('gaussrot',n,theta=theta,nz=nz) - -# one of the target mode changes its variance (no linear mapping) -xt[yt==2]*=3 -xt=xt+4 - - -#%% plot samples - -pl.figure(1,(8,5)) -pl.clf() - -pl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples') -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples') - -pl.legend(loc=0) -pl.title('Source and target distributions') - - - -#%% OT linear mapping estimation - -eta=1e-8 # quadratic regularization for regression -mu=1e0 # weight of the OT linear term -bias=True # estimate a bias - -ot_mapping=ot.da.OTDA_mapping_linear() -ot_mapping.fit(xs,xt,mu=mu,eta=eta,bias=bias,numItermax = 20,verbose=True) - -xst=ot_mapping.predict(xs) # use the estimated mapping -xst0=ot_mapping.interp() # use barycentric mapping - - -pl.figure(2,(10,7)) -pl.clf() -pl.subplot(2,2,1) -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.3) -pl.scatter(xst0[:,0],xst0[:,1],c=ys,marker='+',label='barycentric mapping') -pl.title("barycentric mapping") - -pl.subplot(2,2,2) -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.3) -pl.scatter(xst[:,0],xst[:,1],c=ys,marker='+',label='Learned mapping') -pl.title("Learned mapping") - - - -#%% Kernel mapping estimation - -eta=1e-5 # quadratic regularization for regression -mu=1e-1 # weight of the OT linear term -bias=True # estimate a bias -sigma=1 # sigma bandwidth fot gaussian kernel - - -ot_mapping_kernel=ot.da.OTDA_mapping_kernel() -ot_mapping_kernel.fit(xs,xt,mu=mu,eta=eta,sigma=sigma,bias=bias,numItermax = 10,verbose=True) - -xst_kernel=ot_mapping_kernel.predict(xs) # use the estimated mapping -xst0_kernel=ot_mapping_kernel.interp() # use barycentric mapping - - -#%% Plotting the mapped samples - -pl.figure(2,(10,7)) -pl.clf() -pl.subplot(2,2,1) -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.2) -pl.scatter(xst0[:,0],xst0[:,1],c=ys,marker='+',label='Mapped source samples') -pl.title("Bary. mapping (linear)") -pl.legend(loc=0) - -pl.subplot(2,2,2) -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.2) -pl.scatter(xst[:,0],xst[:,1],c=ys,marker='+',label='Learned mapping') -pl.title("Estim. mapping (linear)") - -pl.subplot(2,2,3) -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.2) -pl.scatter(xst0_kernel[:,0],xst0_kernel[:,1],c=ys,marker='+',label='barycentric mapping') -pl.title("Bary. mapping (kernel)") - -pl.subplot(2,2,4) -pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.2) -pl.scatter(xst_kernel[:,0],xst_kernel[:,1],c=ys,marker='+',label='Learned mapping') -pl.title("Estim. mapping (kernel)") diff --git a/docs/source/auto_examples/plot_OTDA_mapping.rst b/docs/source/auto_examples/plot_OTDA_mapping.rst deleted file mode 100644 index 18da90d..0000000 --- a/docs/source/auto_examples/plot_OTDA_mapping.rst +++ /dev/null @@ -1,186 +0,0 @@ - - -.. _sphx_glr_auto_examples_plot_OTDA_mapping.py: - - -=============================================== -OT mapping estimation for domain adaptation [8] -=============================================== - -[8] M. Perrot, N. Courty, R. Flamary, A. Habrard, "Mapping estimation for - discrete optimal transport", Neural Information Processing Systems (NIPS), 2016. - - - - -.. rst-class:: sphx-glr-horizontal - - - * - - .. image:: /auto_examples/images/sphx_glr_plot_OTDA_mapping_001.png - :scale: 47 - - * - - .. image:: /auto_examples/images/sphx_glr_plot_OTDA_mapping_002.png - :scale: 47 - - -.. rst-class:: sphx-glr-script-out - - Out:: - - It. |Loss |Delta loss - -------------------------------- - 0|4.009366e+03|0.000000e+00 - 1|3.999933e+03|-2.352753e-03 - 2|3.999520e+03|-1.031984e-04 - 3|3.999362e+03|-3.936391e-05 - 4|3.999281e+03|-2.032868e-05 - 5|3.999238e+03|-1.083083e-05 - 6|3.999229e+03|-2.125291e-06 - It. |Loss |Delta loss - -------------------------------- - 0|4.026841e+02|0.000000e+00 - 1|3.990791e+02|-8.952439e-03 - 2|3.987954e+02|-7.107124e-04 - 3|3.986554e+02|-3.512453e-04 - 4|3.985721e+02|-2.087997e-04 - 5|3.985141e+02|-1.456184e-04 - 6|3.984729e+02|-1.034624e-04 - 7|3.984435e+02|-7.366943e-05 - 8|3.984199e+02|-5.922497e-05 - 9|3.984016e+02|-4.593063e-05 - 10|3.983867e+02|-3.733061e-05 - - - - -| - - -.. code-block:: python - - - import numpy as np - import matplotlib.pylab as pl - import ot - - - - #%% dataset generation - - np.random.seed(0) # makes example reproducible - - n=100 # nb samples in source and target datasets - theta=2*np.pi/20 - nz=0.1 - xs,ys=ot.datasets.get_data_classif('gaussrot',n,nz=nz) - xt,yt=ot.datasets.get_data_classif('gaussrot',n,theta=theta,nz=nz) - - # one of the target mode changes its variance (no linear mapping) - xt[yt==2]*=3 - xt=xt+4 - - - #%% plot samples - - pl.figure(1,(8,5)) - pl.clf() - - pl.scatter(xs[:,0],xs[:,1],c=ys,marker='+',label='Source samples') - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples') - - pl.legend(loc=0) - pl.title('Source and target distributions') - - - - #%% OT linear mapping estimation - - eta=1e-8 # quadratic regularization for regression - mu=1e0 # weight of the OT linear term - bias=True # estimate a bias - - ot_mapping=ot.da.OTDA_mapping_linear() - ot_mapping.fit(xs,xt,mu=mu,eta=eta,bias=bias,numItermax = 20,verbose=True) - - xst=ot_mapping.predict(xs) # use the estimated mapping - xst0=ot_mapping.interp() # use barycentric mapping - - - pl.figure(2,(10,7)) - pl.clf() - pl.subplot(2,2,1) - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.3) - pl.scatter(xst0[:,0],xst0[:,1],c=ys,marker='+',label='barycentric mapping') - pl.title("barycentric mapping") - - pl.subplot(2,2,2) - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.3) - pl.scatter(xst[:,0],xst[:,1],c=ys,marker='+',label='Learned mapping') - pl.title("Learned mapping") - - - - #%% Kernel mapping estimation - - eta=1e-5 # quadratic regularization for regression - mu=1e-1 # weight of the OT linear term - bias=True # estimate a bias - sigma=1 # sigma bandwidth fot gaussian kernel - - - ot_mapping_kernel=ot.da.OTDA_mapping_kernel() - ot_mapping_kernel.fit(xs,xt,mu=mu,eta=eta,sigma=sigma,bias=bias,numItermax = 10,verbose=True) - - xst_kernel=ot_mapping_kernel.predict(xs) # use the estimated mapping - xst0_kernel=ot_mapping_kernel.interp() # use barycentric mapping - - - #%% Plotting the mapped samples - - pl.figure(2,(10,7)) - pl.clf() - pl.subplot(2,2,1) - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.2) - pl.scatter(xst0[:,0],xst0[:,1],c=ys,marker='+',label='Mapped source samples') - pl.title("Bary. mapping (linear)") - pl.legend(loc=0) - - pl.subplot(2,2,2) - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.2) - pl.scatter(xst[:,0],xst[:,1],c=ys,marker='+',label='Learned mapping') - pl.title("Estim. mapping (linear)") - - pl.subplot(2,2,3) - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.2) - pl.scatter(xst0_kernel[:,0],xst0_kernel[:,1],c=ys,marker='+',label='barycentric mapping') - pl.title("Bary. mapping (kernel)") - - pl.subplot(2,2,4) - pl.scatter(xt[:,0],xt[:,1],c=yt,marker='o',label='Target samples',alpha=.2) - pl.scatter(xst_kernel[:,0],xst_kernel[:,1],c=ys,marker='+',label='Learned mapping') - pl.title("Estim. mapping (kernel)") - -**Total running time of the script:** ( 0 minutes 0.882 seconds) - - - -.. container:: sphx-glr-footer - - - .. container:: sphx-glr-download - - :download:`Download Python source code: plot_OTDA_mapping.py ` - - - - .. container:: sphx-glr-download - - :download:`Download Jupyter notebook: plot_OTDA_mapping.ipynb ` - -.. rst-class:: sphx-glr-signature - - `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_OTDA_mapping_color_images.ipynb b/docs/source/auto_examples/plot_OTDA_mapping_color_images.ipynb deleted file mode 100644 index 1136cc3..0000000 --- a/docs/source/auto_examples/plot_OTDA_mapping_color_images.ipynb +++ /dev/null @@ -1,54 +0,0 @@ -{ - "nbformat_minor": 0, - "nbformat": 4, - "cells": [ - { - "execution_count": null, - "cell_type": "code", - "source": [ - "%matplotlib inline" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - }, - { - "source": [ - "\n====================================================================================\nOT for domain adaptation with image color adaptation [6] with mapping estimation [8]\n====================================================================================\n\n[6] Ferradans, S., Papadakis, N., Peyre, G., & Aujol, J. F. (2014). Regularized\n discrete optimal transport. SIAM Journal on Imaging Sciences, 7(3), 1853-1882.\n[8] M. Perrot, N. Courty, R. Flamary, A. Habrard, \"Mapping estimation for\n discrete optimal transport\", Neural Information Processing Systems (NIPS), 2016.\n\n\n" - ], - "cell_type": "markdown", - "metadata": {} - }, - { - "execution_count": null, - "cell_type": "code", - "source": [ - "import numpy as np\nimport scipy.ndimage as spi\nimport matplotlib.pylab as pl\nimport ot\n\n\n#%% Loading images\n\nI1=spi.imread('../data/ocean_day.jpg').astype(np.float64)/256\nI2=spi.imread('../data/ocean_sunset.jpg').astype(np.float64)/256\n\n#%% Plot images\n\npl.figure(1)\n\npl.subplot(1,2,1)\npl.imshow(I1)\npl.title('Image 1')\n\npl.subplot(1,2,2)\npl.imshow(I2)\npl.title('Image 2')\n\npl.show()\n\n#%% Image conversion and dataset generation\n\ndef im2mat(I):\n \"\"\"Converts and image to matrix (one pixel per line)\"\"\"\n return I.reshape((I.shape[0]*I.shape[1],I.shape[2]))\n\ndef mat2im(X,shape):\n \"\"\"Converts back a matrix to an image\"\"\"\n return X.reshape(shape)\n\nX1=im2mat(I1)\nX2=im2mat(I2)\n\n# training samples\nnb=1000\nidx1=np.random.randint(X1.shape[0],size=(nb,))\nidx2=np.random.randint(X2.shape[0],size=(nb,))\n\nxs=X1[idx1,:]\nxt=X2[idx2,:]\n\n#%% Plot image distributions\n\n\npl.figure(2,(10,5))\n\npl.subplot(1,2,1)\npl.scatter(xs[:,0],xs[:,2],c=xs)\npl.axis([0,1,0,1])\npl.xlabel('Red')\npl.ylabel('Blue')\npl.title('Image 1')\n\npl.subplot(1,2,2)\n#pl.imshow(I2)\npl.scatter(xt[:,0],xt[:,2],c=xt)\npl.axis([0,1,0,1])\npl.xlabel('Red')\npl.ylabel('Blue')\npl.title('Image 2')\n\npl.show()\n\n\n\n#%% domain adaptation between images\ndef minmax(I):\n return np.minimum(np.maximum(I,0),1)\n# LP problem\nda_emd=ot.da.OTDA() # init class\nda_emd.fit(xs,xt) # fit distributions\n\nX1t=da_emd.predict(X1) # out of sample\nI1t=minmax(mat2im(X1t,I1.shape))\n\n# sinkhorn regularization\nlambd=1e-1\nda_entrop=ot.da.OTDA_sinkhorn()\nda_entrop.fit(xs,xt,reg=lambd)\n\nX1te=da_entrop.predict(X1)\nI1te=minmax(mat2im(X1te,I1.shape))\n\n# linear mapping estimation\neta=1e-8 # quadratic regularization for regression\nmu=1e0 # weight of the OT linear term\nbias=True # estimate a bias\n\not_mapping=ot.da.OTDA_mapping_linear()\not_mapping.fit(xs,xt,mu=mu,eta=eta,bias=bias,numItermax = 20,verbose=True)\n\nX1tl=ot_mapping.predict(X1) # use the estimated mapping\nI1tl=minmax(mat2im(X1tl,I1.shape))\n\n# nonlinear mapping estimation\neta=1e-2 # quadratic regularization for regression\nmu=1e0 # weight of the OT linear term\nbias=False # estimate a bias\nsigma=1 # sigma bandwidth fot gaussian kernel\n\n\not_mapping_kernel=ot.da.OTDA_mapping_kernel()\not_mapping_kernel.fit(xs,xt,mu=mu,eta=eta,sigma=sigma,bias=bias,numItermax = 10,verbose=True)\n\nX1tn=ot_mapping_kernel.predict(X1) # use the estimated mapping\nI1tn=minmax(mat2im(X1tn,I1.shape))\n#%% plot images\n\n\npl.figure(2,(10,8))\n\npl.subplot(2,3,1)\n\npl.imshow(I1)\npl.title('Im. 1')\n\npl.subplot(2,3,2)\n\npl.imshow(I2)\npl.title('Im. 2')\n\n\npl.subplot(2,3,3)\npl.imshow(I1t)\npl.title('Im. 1 Interp LP')\n\npl.subplot(2,3,4)\npl.imshow(I1te)\npl.title('Im. 1 Interp Entrop')\n\n\npl.subplot(2,3,5)\npl.imshow(I1tl)\npl.title('Im. 1 Linear mapping')\n\npl.subplot(2,3,6)\npl.imshow(I1tn)\npl.title('Im. 1 nonlinear mapping')\n\npl.show()" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 2", - "name": "python2", - "language": "python" - }, - "language_info": { - "mimetype": "text/x-python", - "nbconvert_exporter": "python", - "name": "python", - "file_extension": ".py", - "version": "2.7.12", - "pygments_lexer": "ipython2", - "codemirror_mode": { - "version": 2, - "name": "ipython" - } - } - } -} \ No newline at end of file diff --git a/docs/source/auto_examples/plot_OTDA_mapping_color_images.py b/docs/source/auto_examples/plot_OTDA_mapping_color_images.py deleted file mode 100644 index f07dc6c..0000000 --- a/docs/source/auto_examples/plot_OTDA_mapping_color_images.py +++ /dev/null @@ -1,158 +0,0 @@ -# -*- coding: utf-8 -*- -""" -==================================================================================== -OT for domain adaptation with image color adaptation [6] with mapping estimation [8] -==================================================================================== - -[6] Ferradans, S., Papadakis, N., Peyre, G., & Aujol, J. F. (2014). Regularized - discrete optimal transport. SIAM Journal on Imaging Sciences, 7(3), 1853-1882. -[8] M. Perrot, N. Courty, R. Flamary, A. Habrard, "Mapping estimation for - discrete optimal transport", Neural Information Processing Systems (NIPS), 2016. - -""" - -import numpy as np -import scipy.ndimage as spi -import matplotlib.pylab as pl -import ot - - -#%% Loading images - -I1=spi.imread('../data/ocean_day.jpg').astype(np.float64)/256 -I2=spi.imread('../data/ocean_sunset.jpg').astype(np.float64)/256 - -#%% Plot images - -pl.figure(1) - -pl.subplot(1,2,1) -pl.imshow(I1) -pl.title('Image 1') - -pl.subplot(1,2,2) -pl.imshow(I2) -pl.title('Image 2') - -pl.show() - -#%% Image conversion and dataset generation - -def im2mat(I): - """Converts and image to matrix (one pixel per line)""" - return I.reshape((I.shape[0]*I.shape[1],I.shape[2])) - -def mat2im(X,shape): - """Converts back a matrix to an image""" - return X.reshape(shape) - -X1=im2mat(I1) -X2=im2mat(I2) - -# training samples -nb=1000 -idx1=np.random.randint(X1.shape[0],size=(nb,)) -idx2=np.random.randint(X2.shape[0],size=(nb,)) - -xs=X1[idx1,:] -xt=X2[idx2,:] - -#%% Plot image distributions - - -pl.figure(2,(10,5)) - -pl.subplot(1,2,1) -pl.scatter(xs[:,0],xs[:,2],c=xs) -pl.axis([0,1,0,1]) -pl.xlabel('Red') -pl.ylabel('Blue') -pl.title('Image 1') - -pl.subplot(1,2,2) -#pl.imshow(I2) -pl.scatter(xt[:,0],xt[:,2],c=xt) -pl.axis([0,1,0,1]) -pl.xlabel('Red') -pl.ylabel('Blue') -pl.title('Image 2') - -pl.show() - - - -#%% domain adaptation between images -def minmax(I): - return np.minimum(np.maximum(I,0),1) -# LP problem -da_emd=ot.da.OTDA() # init class -da_emd.fit(xs,xt) # fit distributions - -X1t=da_emd.predict(X1) # out of sample -I1t=minmax(mat2im(X1t,I1.shape)) - -# sinkhorn regularization -lambd=1e-1 -da_entrop=ot.da.OTDA_sinkhorn() -da_entrop.fit(xs,xt,reg=lambd) - -X1te=da_entrop.predict(X1) -I1te=minmax(mat2im(X1te,I1.shape)) - -# linear mapping estimation -eta=1e-8 # quadratic regularization for regression -mu=1e0 # weight of the OT linear term -bias=True # estimate a bias - -ot_mapping=ot.da.OTDA_mapping_linear() -ot_mapping.fit(xs,xt,mu=mu,eta=eta,bias=bias,numItermax = 20,verbose=True) - -X1tl=ot_mapping.predict(X1) # use the estimated mapping -I1tl=minmax(mat2im(X1tl,I1.shape)) - -# nonlinear mapping estimation -eta=1e-2 # quadratic regularization for regression -mu=1e0 # weight of the OT linear term -bias=False # estimate a bias -sigma=1 # sigma bandwidth fot gaussian kernel - - -ot_mapping_kernel=ot.da.OTDA_mapping_kernel() -ot_mapping_kernel.fit(xs,xt,mu=mu,eta=eta,sigma=sigma,bias=bias,numItermax = 10,verbose=True) - -X1tn=ot_mapping_kernel.predict(X1) # use the estimated mapping -I1tn=minmax(mat2im(X1tn,I1.shape)) -#%% plot images - - -pl.figure(2,(10,8)) - -pl.subplot(2,3,1) - -pl.imshow(I1) -pl.title('Im. 1') - -pl.subplot(2,3,2) - -pl.imshow(I2) -pl.title('Im. 2') - - -pl.subplot(2,3,3) -pl.imshow(I1t) -pl.title('Im. 1 Interp LP') - -pl.subplot(2,3,4) -pl.imshow(I1te) -pl.title('Im. 1 Interp Entrop') - - -pl.subplot(2,3,5) -pl.imshow(I1tl) -pl.title('Im. 1 Linear mapping') - -pl.subplot(2,3,6) -pl.imshow(I1tn) -pl.title('Im. 1 nonlinear mapping') - -pl.show() diff --git a/docs/source/auto_examples/plot_OTDA_mapping_color_images.rst b/docs/source/auto_examples/plot_OTDA_mapping_color_images.rst deleted file mode 100644 index 60be3a4..0000000 --- a/docs/source/auto_examples/plot_OTDA_mapping_color_images.rst +++ /dev/null @@ -1,246 +0,0 @@ - - -.. _sphx_glr_auto_examples_plot_OTDA_mapping_color_images.py: - - -==================================================================================== -OT for domain adaptation with image color adaptation [6] with mapping estimation [8] -==================================================================================== - -[6] Ferradans, S., Papadakis, N., Peyre, G., & Aujol, J. F. (2014). Regularized - discrete optimal transport. SIAM Journal on Imaging Sciences, 7(3), 1853-1882. -[8] M. Perrot, N. Courty, R. Flamary, A. Habrard, "Mapping estimation for - discrete optimal transport", Neural Information Processing Systems (NIPS), 2016. - - - - - -.. rst-class:: sphx-glr-horizontal - - - * - - .. image:: /auto_examples/images/sphx_glr_plot_OTDA_mapping_color_images_001.png - :scale: 47 - - * - - .. image:: /auto_examples/images/sphx_glr_plot_OTDA_mapping_color_images_002.png - :scale: 47 - - -.. rst-class:: sphx-glr-script-out - - Out:: - - It. |Loss |Delta loss - -------------------------------- - 0|3.624802e+02|0.000000e+00 - 1|3.547180e+02|-2.141395e-02 - 2|3.545494e+02|-4.753955e-04 - 3|3.544646e+02|-2.391784e-04 - 4|3.544126e+02|-1.466280e-04 - 5|3.543775e+02|-9.921805e-05 - 6|3.543518e+02|-7.245828e-05 - 7|3.543323e+02|-5.491924e-05 - 8|3.543170e+02|-4.342401e-05 - 9|3.543046e+02|-3.472174e-05 - 10|3.542945e+02|-2.878681e-05 - 11|3.542859e+02|-2.417065e-05 - 12|3.542786e+02|-2.058131e-05 - 13|3.542723e+02|-1.768262e-05 - 14|3.542668e+02|-1.551616e-05 - 15|3.542620e+02|-1.371909e-05 - 16|3.542577e+02|-1.213326e-05 - 17|3.542538e+02|-1.085481e-05 - 18|3.542531e+02|-1.996006e-06 - It. |Loss |Delta loss - -------------------------------- - 0|3.555768e+02|0.000000e+00 - 1|3.510071e+02|-1.285164e-02 - 2|3.509110e+02|-2.736701e-04 - 3|3.508748e+02|-1.031476e-04 - 4|3.508506e+02|-6.910585e-05 - 5|3.508330e+02|-5.014608e-05 - 6|3.508195e+02|-3.839166e-05 - 7|3.508090e+02|-3.004218e-05 - 8|3.508005e+02|-2.417627e-05 - 9|3.507935e+02|-2.004621e-05 - 10|3.507876e+02|-1.681731e-05 - - - - -| - - -.. code-block:: python - - - import numpy as np - import scipy.ndimage as spi - import matplotlib.pylab as pl - import ot - - - #%% Loading images - - I1=spi.imread('../data/ocean_day.jpg').astype(np.float64)/256 - I2=spi.imread('../data/ocean_sunset.jpg').astype(np.float64)/256 - - #%% Plot images - - pl.figure(1) - - pl.subplot(1,2,1) - pl.imshow(I1) - pl.title('Image 1') - - pl.subplot(1,2,2) - pl.imshow(I2) - pl.title('Image 2') - - pl.show() - - #%% Image conversion and dataset generation - - def im2mat(I): - """Converts and image to matrix (one pixel per line)""" - return I.reshape((I.shape[0]*I.shape[1],I.shape[2])) - - def mat2im(X,shape): - """Converts back a matrix to an image""" - return X.reshape(shape) - - X1=im2mat(I1) - X2=im2mat(I2) - - # training samples - nb=1000 - idx1=np.random.randint(X1.shape[0],size=(nb,)) - idx2=np.random.randint(X2.shape[0],size=(nb,)) - - xs=X1[idx1,:] - xt=X2[idx2,:] - - #%% Plot image distributions - - - pl.figure(2,(10,5)) - - pl.subplot(1,2,1) - pl.scatter(xs[:,0],xs[:,2],c=xs) - pl.axis([0,1,0,1]) - pl.xlabel('Red') - pl.ylabel('Blue') - pl.title('Image 1') - - pl.subplot(1,2,2) - #pl.imshow(I2) - pl.scatter(xt[:,0],xt[:,2],c=xt) - pl.axis([0,1,0,1]) - pl.xlabel('Red') - pl.ylabel('Blue') - pl.title('Image 2') - - pl.show() - - - - #%% domain adaptation between images - def minmax(I): - return np.minimum(np.maximum(I,0),1) - # LP problem - da_emd=ot.da.OTDA() # init class - da_emd.fit(xs,xt) # fit distributions - - X1t=da_emd.predict(X1) # out of sample - I1t=minmax(mat2im(X1t,I1.shape)) - - # sinkhorn regularization - lambd=1e-1 - da_entrop=ot.da.OTDA_sinkhorn() - da_entrop.fit(xs,xt,reg=lambd) - - X1te=da_entrop.predict(X1) - I1te=minmax(mat2im(X1te,I1.shape)) - - # linear mapping estimation - eta=1e-8 # quadratic regularization for regression - mu=1e0 # weight of the OT linear term - bias=True # estimate a bias - - ot_mapping=ot.da.OTDA_mapping_linear() - ot_mapping.fit(xs,xt,mu=mu,eta=eta,bias=bias,numItermax = 20,verbose=True) - - X1tl=ot_mapping.predict(X1) # use the estimated mapping - I1tl=minmax(mat2im(X1tl,I1.shape)) - - # nonlinear mapping estimation - eta=1e-2 # quadratic regularization for regression - mu=1e0 # weight of the OT linear term - bias=False # estimate a bias - sigma=1 # sigma bandwidth fot gaussian kernel - - - ot_mapping_kernel=ot.da.OTDA_mapping_kernel() - ot_mapping_kernel.fit(xs,xt,mu=mu,eta=eta,sigma=sigma,bias=bias,numItermax = 10,verbose=True) - - X1tn=ot_mapping_kernel.predict(X1) # use the estimated mapping - I1tn=minmax(mat2im(X1tn,I1.shape)) - #%% plot images - - - pl.figure(2,(10,8)) - - pl.subplot(2,3,1) - - pl.imshow(I1) - pl.title('Im. 1') - - pl.subplot(2,3,2) - - pl.imshow(I2) - pl.title('Im. 2') - - - pl.subplot(2,3,3) - pl.imshow(I1t) - pl.title('Im. 1 Interp LP') - - pl.subplot(2,3,4) - pl.imshow(I1te) - pl.title('Im. 1 Interp Entrop') - - - pl.subplot(2,3,5) - pl.imshow(I1tl) - pl.title('Im. 1 Linear mapping') - - pl.subplot(2,3,6) - pl.imshow(I1tn) - pl.title('Im. 1 nonlinear mapping') - - pl.show() - -**Total running time of the script:** ( 1 minutes 59.537 seconds) - - - -.. container:: sphx-glr-footer - - - .. container:: sphx-glr-download - - :download:`Download Python source code: plot_OTDA_mapping_color_images.py ` - - - - .. container:: sphx-glr-download - - :download:`Download Jupyter notebook: plot_OTDA_mapping_color_images.ipynb ` - -.. rst-class:: sphx-glr-signature - - `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_OT_1D.ipynb b/docs/source/auto_examples/plot_OT_1D.ipynb index 97c593e..3126b6f 100644 --- a/docs/source/auto_examples/plot_OT_1D.ipynb +++ b/docs/source/auto_examples/plot_OT_1D.ipynb @@ -15,7 +15,7 @@ }, { "source": [ - "\n# 1D optimal transport\n\n\n\n" + "\n# 1D optimal transport\n\n\nThis example illustrates the computation of EMD and Sinkhorn transport plans \nand their visualization.\n\n\n" ], "cell_type": "markdown", "metadata": {} @@ -69,7 +69,7 @@ }, { "source": [ - "Solve EMD \n#############################################################################\n\n" + "Solve EMD\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_OT_1D.py b/docs/source/auto_examples/plot_OT_1D.py index be6f5b3..a63f29a 100644 --- a/docs/source/auto_examples/plot_OT_1D.py +++ b/docs/source/auto_examples/plot_OT_1D.py @@ -4,6 +4,9 @@ 1D optimal transport ==================== +This example illustrates the computation of EMD and Sinkhorn transport plans +and their visualization. + """ # Author: Remi Flamary @@ -52,7 +55,7 @@ pl.figure(2, figsize=(5, 5)) ot.plot.plot1D_mat(a, b, M, 'Cost matrix M') ############################################################################## -# Solve EMD +# Solve EMD ############################################################################## #%% EMD diff --git a/docs/source/auto_examples/plot_OT_1D.rst b/docs/source/auto_examples/plot_OT_1D.rst index 252d387..ff02180 100644 --- a/docs/source/auto_examples/plot_OT_1D.rst +++ b/docs/source/auto_examples/plot_OT_1D.rst @@ -7,6 +7,9 @@ 1D optimal transport ==================== +This example illustrates the computation of EMD and Sinkhorn transport plans +and their visualization. + @@ -97,7 +100,7 @@ Plot distributions and loss matrix -Solve EMD +Solve EMD ############################################################################# @@ -165,7 +168,7 @@ Solve Sinkhorn 110|1.527180e-10| -**Total running time of the script:** ( 0 minutes 1.065 seconds) +**Total running time of the script:** ( 0 minutes 0.770 seconds) @@ -184,4 +187,4 @@ Solve Sinkhorn .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_OT_2D_samples.ipynb b/docs/source/auto_examples/plot_OT_2D_samples.ipynb index fc4ce50..0ed7367 100644 --- a/docs/source/auto_examples/plot_OT_2D_samples.ipynb +++ b/docs/source/auto_examples/plot_OT_2D_samples.ipynb @@ -15,7 +15,7 @@ }, { "source": [ - "\n# 2D Optimal transport between empirical distributions\n\n\n\n" + "\n# 2D Optimal transport between empirical distributions\n\n\nIllustration of 2D optimal transport between discributions that are weighted\nsum of diracs. The OT matrix is plotted with the samples.\n\n\n" ], "cell_type": "markdown", "metadata": {} @@ -24,7 +24,79 @@ "execution_count": null, "cell_type": "code", "source": [ - "# Author: Remi Flamary \n#\n# License: MIT License\n\nimport numpy as np\nimport matplotlib.pylab as pl\nimport ot\n\n#%% parameters and data generation\n\nn = 50 # nb samples\n\nmu_s = np.array([0, 0])\ncov_s = np.array([[1, 0], [0, 1]])\n\nmu_t = np.array([4, 4])\ncov_t = np.array([[1, -.8], [-.8, 1]])\n\nxs = ot.datasets.get_2D_samples_gauss(n, mu_s, cov_s)\nxt = ot.datasets.get_2D_samples_gauss(n, mu_t, cov_t)\n\na, b = np.ones((n,)) / n, np.ones((n,)) / n # uniform distribution on samples\n\n# loss matrix\nM = ot.dist(xs, xt)\nM /= M.max()\n\n#%% plot samples\n\npl.figure(1)\npl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\npl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\npl.legend(loc=0)\npl.title('Source and target distributions')\n\npl.figure(2)\npl.imshow(M, interpolation='nearest')\npl.title('Cost matrix M')\n\n\n#%% EMD\n\nG0 = ot.emd(a, b, M)\n\npl.figure(3)\npl.imshow(G0, interpolation='nearest')\npl.title('OT matrix G0')\n\npl.figure(4)\not.plot.plot2D_samples_mat(xs, xt, G0, c=[.5, .5, 1])\npl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\npl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\npl.legend(loc=0)\npl.title('OT matrix with samples')\n\n\n#%% sinkhorn\n\n# reg term\nlambd = 1e-3\n\nGs = ot.sinkhorn(a, b, M, lambd)\n\npl.figure(5)\npl.imshow(Gs, interpolation='nearest')\npl.title('OT matrix sinkhorn')\n\npl.figure(6)\not.plot.plot2D_samples_mat(xs, xt, Gs, color=[.5, .5, 1])\npl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\npl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\npl.legend(loc=0)\npl.title('OT matrix Sinkhorn with samples')\n\npl.show()" + "# Author: Remi Flamary \n#\n# License: MIT License\n\nimport numpy as np\nimport matplotlib.pylab as pl\nimport ot" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Generate data\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% parameters and data generation\n\nn = 50 # nb samples\n\nmu_s = np.array([0, 0])\ncov_s = np.array([[1, 0], [0, 1]])\n\nmu_t = np.array([4, 4])\ncov_t = np.array([[1, -.8], [-.8, 1]])\n\nxs = ot.datasets.get_2D_samples_gauss(n, mu_s, cov_s)\nxt = ot.datasets.get_2D_samples_gauss(n, mu_t, cov_t)\n\na, b = np.ones((n,)) / n, np.ones((n,)) / n # uniform distribution on samples\n\n# loss matrix\nM = ot.dist(xs, xt)\nM /= M.max()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Plot data\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% plot samples\n\npl.figure(1)\npl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\npl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\npl.legend(loc=0)\npl.title('Source and target distributions')\n\npl.figure(2)\npl.imshow(M, interpolation='nearest')\npl.title('Cost matrix M')" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Compute EMD\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% EMD\n\nG0 = ot.emd(a, b, M)\n\npl.figure(3)\npl.imshow(G0, interpolation='nearest')\npl.title('OT matrix G0')\n\npl.figure(4)\not.plot.plot2D_samples_mat(xs, xt, G0, c=[.5, .5, 1])\npl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\npl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\npl.legend(loc=0)\npl.title('OT matrix with samples')" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Compute Sinkhorn\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% sinkhorn\n\n# reg term\nlambd = 1e-3\n\nGs = ot.sinkhorn(a, b, M, lambd)\n\npl.figure(5)\npl.imshow(Gs, interpolation='nearest')\npl.title('OT matrix sinkhorn')\n\npl.figure(6)\not.plot.plot2D_samples_mat(xs, xt, Gs, color=[.5, .5, 1])\npl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\npl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\npl.legend(loc=0)\npl.title('OT matrix Sinkhorn with samples')\n\npl.show()" ], "outputs": [], "metadata": { diff --git a/docs/source/auto_examples/plot_OT_2D_samples.py b/docs/source/auto_examples/plot_OT_2D_samples.py index 2a42dc0..f57d631 100644 --- a/docs/source/auto_examples/plot_OT_2D_samples.py +++ b/docs/source/auto_examples/plot_OT_2D_samples.py @@ -4,6 +4,9 @@ 2D Optimal transport between empirical distributions ==================================================== +Illustration of 2D optimal transport between discributions that are weighted +sum of diracs. The OT matrix is plotted with the samples. + """ # Author: Remi Flamary @@ -14,6 +17,10 @@ import numpy as np import matplotlib.pylab as pl import ot +############################################################################## +# Generate data +############################################################################## + #%% parameters and data generation n = 50 # nb samples @@ -33,6 +40,10 @@ a, b = np.ones((n,)) / n, np.ones((n,)) / n # uniform distribution on samples M = ot.dist(xs, xt) M /= M.max() +############################################################################## +# Plot data +############################################################################## + #%% plot samples pl.figure(1) @@ -45,6 +56,9 @@ pl.figure(2) pl.imshow(M, interpolation='nearest') pl.title('Cost matrix M') +############################################################################## +# Compute EMD +############################################################################## #%% EMD @@ -62,6 +76,10 @@ pl.legend(loc=0) pl.title('OT matrix with samples') +############################################################################## +# Compute Sinkhorn +############################################################################## + #%% sinkhorn # reg term diff --git a/docs/source/auto_examples/plot_OT_2D_samples.rst b/docs/source/auto_examples/plot_OT_2D_samples.rst index c472c6a..f95ffaf 100644 --- a/docs/source/auto_examples/plot_OT_2D_samples.rst +++ b/docs/source/auto_examples/plot_OT_2D_samples.rst @@ -7,58 +7,37 @@ 2D Optimal transport between empirical distributions ==================================================== +Illustration of 2D optimal transport between discributions that are weighted +sum of diracs. The OT matrix is plotted with the samples. -.. rst-class:: sphx-glr-horizontal - - - * - - .. image:: /auto_examples/images/sphx_glr_plot_OT_2D_samples_001.png - :scale: 47 - - * - - .. image:: /auto_examples/images/sphx_glr_plot_OT_2D_samples_002.png - :scale: 47 +.. code-block:: python - * - .. image:: /auto_examples/images/sphx_glr_plot_OT_2D_samples_003.png - :scale: 47 + # Author: Remi Flamary + # + # License: MIT License - * + import numpy as np + import matplotlib.pylab as pl + import ot - .. image:: /auto_examples/images/sphx_glr_plot_OT_2D_samples_004.png - :scale: 47 - * - .. image:: /auto_examples/images/sphx_glr_plot_OT_2D_samples_005.png - :scale: 47 - * - .. image:: /auto_examples/images/sphx_glr_plot_OT_2D_samples_006.png - :scale: 47 +Generate data +############################################################################# .. code-block:: python - # Author: Remi Flamary - # - # License: MIT License - - import numpy as np - import matplotlib.pylab as pl - import ot - #%% parameters and data generation n = 50 # nb samples @@ -78,6 +57,20 @@ M = ot.dist(xs, xt) M /= M.max() + + + + + + +Plot data +############################################################################# + + + +.. code-block:: python + + #%% plot samples pl.figure(1) @@ -91,6 +84,32 @@ pl.title('Cost matrix M') + + +.. rst-class:: sphx-glr-horizontal + + + * + + .. image:: /auto_examples/images/sphx_glr_plot_OT_2D_samples_001.png + :scale: 47 + + * + + .. image:: /auto_examples/images/sphx_glr_plot_OT_2D_samples_002.png + :scale: 47 + + + + +Compute EMD +############################################################################# + + + +.. code-block:: python + + #%% EMD G0 = ot.emd(a, b, M) @@ -107,6 +126,33 @@ pl.title('OT matrix with samples') + + + +.. rst-class:: sphx-glr-horizontal + + + * + + .. image:: /auto_examples/images/sphx_glr_plot_OT_2D_samples_005.png + :scale: 47 + + * + + .. image:: /auto_examples/images/sphx_glr_plot_OT_2D_samples_006.png + :scale: 47 + + + + +Compute Sinkhorn +############################################################################# + + + +.. code-block:: python + + #%% sinkhorn # reg term @@ -127,7 +173,25 @@ pl.show() -**Total running time of the script:** ( 0 minutes 2.908 seconds) + + +.. rst-class:: sphx-glr-horizontal + + + * + + .. image:: /auto_examples/images/sphx_glr_plot_OT_2D_samples_009.png + :scale: 47 + + * + + .. image:: /auto_examples/images/sphx_glr_plot_OT_2D_samples_010.png + :scale: 47 + + + + +**Total running time of the script:** ( 0 minutes 1.990 seconds) @@ -146,4 +210,4 @@ .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_OT_L1_vs_L2.ipynb b/docs/source/auto_examples/plot_OT_L1_vs_L2.ipynb index 04ef5c8..e738db7 100644 --- a/docs/source/auto_examples/plot_OT_L1_vs_L2.ipynb +++ b/docs/source/auto_examples/plot_OT_L1_vs_L2.ipynb @@ -15,7 +15,7 @@ }, { "source": [ - "\n# 2D Optimal transport for different metrics\n\n\nStole the figure idea from Fig. 1 and 2 in\nhttps://arxiv.org/pdf/1706.07650.pdf\n\n\n\n" + "\n# 2D Optimal transport for different metrics\n\n\n2D OT on empirical distributio with different gound metric.\n\nStole the figure idea from Fig. 1 and 2 in\nhttps://arxiv.org/pdf/1706.07650.pdf\n\n\n\n" ], "cell_type": "markdown", "metadata": {} @@ -24,7 +24,79 @@ "execution_count": null, "cell_type": "code", "source": [ - "# Author: Remi Flamary \n#\n# License: MIT License\n\nimport numpy as np\nimport matplotlib.pylab as pl\nimport ot\n\n#%% parameters and data generation\n\nfor data in range(2):\n\n if data:\n n = 20 # nb samples\n xs = np.zeros((n, 2))\n xs[:, 0] = np.arange(n) + 1\n xs[:, 1] = (np.arange(n) + 1) * -0.001 # to make it strictly convex...\n\n xt = np.zeros((n, 2))\n xt[:, 1] = np.arange(n) + 1\n else:\n\n n = 50 # nb samples\n xtot = np.zeros((n + 1, 2))\n xtot[:, 0] = np.cos(\n (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi)\n xtot[:, 1] = np.sin(\n (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi)\n\n xs = xtot[:n, :]\n xt = xtot[1:, :]\n\n a, b = ot.unif(n), ot.unif(n) # uniform distribution on samples\n\n # loss matrix\n M1 = ot.dist(xs, xt, metric='euclidean')\n M1 /= M1.max()\n\n # loss matrix\n M2 = ot.dist(xs, xt, metric='sqeuclidean')\n M2 /= M2.max()\n\n # loss matrix\n Mp = np.sqrt(ot.dist(xs, xt, metric='euclidean'))\n Mp /= Mp.max()\n\n #%% plot samples\n\n pl.figure(1 + 3 * data, figsize=(7, 3))\n pl.clf()\n pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\n pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\n pl.axis('equal')\n pl.title('Source and traget distributions')\n\n pl.figure(2 + 3 * data, figsize=(7, 3))\n\n pl.subplot(1, 3, 1)\n pl.imshow(M1, interpolation='nearest')\n pl.title('Euclidean cost')\n\n pl.subplot(1, 3, 2)\n pl.imshow(M2, interpolation='nearest')\n pl.title('Squared Euclidean cost')\n\n pl.subplot(1, 3, 3)\n pl.imshow(Mp, interpolation='nearest')\n pl.title('Sqrt Euclidean cost')\n pl.tight_layout()\n\n #%% EMD\n G1 = ot.emd(a, b, M1)\n G2 = ot.emd(a, b, M2)\n Gp = ot.emd(a, b, Mp)\n\n pl.figure(3 + 3 * data, figsize=(7, 3))\n\n pl.subplot(1, 3, 1)\n ot.plot.plot2D_samples_mat(xs, xt, G1, c=[.5, .5, 1])\n pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\n pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\n pl.axis('equal')\n # pl.legend(loc=0)\n pl.title('OT Euclidean')\n\n pl.subplot(1, 3, 2)\n ot.plot.plot2D_samples_mat(xs, xt, G2, c=[.5, .5, 1])\n pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\n pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\n pl.axis('equal')\n # pl.legend(loc=0)\n pl.title('OT squared Euclidean')\n\n pl.subplot(1, 3, 3)\n ot.plot.plot2D_samples_mat(xs, xt, Gp, c=[.5, .5, 1])\n pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\n pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\n pl.axis('equal')\n # pl.legend(loc=0)\n pl.title('OT sqrt Euclidean')\n pl.tight_layout()\n\npl.show()" + "# Author: Remi Flamary \n#\n# License: MIT License\n\nimport numpy as np\nimport matplotlib.pylab as pl\nimport ot" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Dataset 1 : uniform sampling\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "n = 20 # nb samples\nxs = np.zeros((n, 2))\nxs[:, 0] = np.arange(n) + 1\nxs[:, 1] = (np.arange(n) + 1) * -0.001 # to make it strictly convex...\n\nxt = np.zeros((n, 2))\nxt[:, 1] = np.arange(n) + 1\n\na, b = ot.unif(n), ot.unif(n) # uniform distribution on samples\n\n# loss matrix\nM1 = ot.dist(xs, xt, metric='euclidean')\nM1 /= M1.max()\n\n# loss matrix\nM2 = ot.dist(xs, xt, metric='sqeuclidean')\nM2 /= M2.max()\n\n# loss matrix\nMp = np.sqrt(ot.dist(xs, xt, metric='euclidean'))\nMp /= Mp.max()\n\n# Data\npl.figure(1, figsize=(7, 3))\npl.clf()\npl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\npl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\npl.axis('equal')\npl.title('Source and traget distributions')\n\n\n# Cost matrices\npl.figure(2, figsize=(7, 3))\n\npl.subplot(1, 3, 1)\npl.imshow(M1, interpolation='nearest')\npl.title('Euclidean cost')\n\npl.subplot(1, 3, 2)\npl.imshow(M2, interpolation='nearest')\npl.title('Squared Euclidean cost')\n\npl.subplot(1, 3, 3)\npl.imshow(Mp, interpolation='nearest')\npl.title('Sqrt Euclidean cost')\npl.tight_layout()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Dataset 1 : Plot OT Matrices\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% EMD\nG1 = ot.emd(a, b, M1)\nG2 = ot.emd(a, b, M2)\nGp = ot.emd(a, b, Mp)\n\n# OT matrices\npl.figure(3, figsize=(7, 3))\n\npl.subplot(1, 3, 1)\not.plot.plot2D_samples_mat(xs, xt, G1, c=[.5, .5, 1])\npl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\npl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\npl.axis('equal')\n# pl.legend(loc=0)\npl.title('OT Euclidean')\n\npl.subplot(1, 3, 2)\not.plot.plot2D_samples_mat(xs, xt, G2, c=[.5, .5, 1])\npl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\npl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\npl.axis('equal')\n# pl.legend(loc=0)\npl.title('OT squared Euclidean')\n\npl.subplot(1, 3, 3)\not.plot.plot2D_samples_mat(xs, xt, Gp, c=[.5, .5, 1])\npl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\npl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\npl.axis('equal')\n# pl.legend(loc=0)\npl.title('OT sqrt Euclidean')\npl.tight_layout()\n\npl.show()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Dataset 2 : Partial circle\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "n = 50 # nb samples\nxtot = np.zeros((n + 1, 2))\nxtot[:, 0] = np.cos(\n (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi)\nxtot[:, 1] = np.sin(\n (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi)\n\nxs = xtot[:n, :]\nxt = xtot[1:, :]\n\na, b = ot.unif(n), ot.unif(n) # uniform distribution on samples\n\n# loss matrix\nM1 = ot.dist(xs, xt, metric='euclidean')\nM1 /= M1.max()\n\n# loss matrix\nM2 = ot.dist(xs, xt, metric='sqeuclidean')\nM2 /= M2.max()\n\n# loss matrix\nMp = np.sqrt(ot.dist(xs, xt, metric='euclidean'))\nMp /= Mp.max()\n\n\n# Data\npl.figure(4, figsize=(7, 3))\npl.clf()\npl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\npl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\npl.axis('equal')\npl.title('Source and traget distributions')\n\n\n# Cost matrices\npl.figure(5, figsize=(7, 3))\n\npl.subplot(1, 3, 1)\npl.imshow(M1, interpolation='nearest')\npl.title('Euclidean cost')\n\npl.subplot(1, 3, 2)\npl.imshow(M2, interpolation='nearest')\npl.title('Squared Euclidean cost')\n\npl.subplot(1, 3, 3)\npl.imshow(Mp, interpolation='nearest')\npl.title('Sqrt Euclidean cost')\npl.tight_layout()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Dataset 2 : Plot OT Matrices\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% EMD\nG1 = ot.emd(a, b, M1)\nG2 = ot.emd(a, b, M2)\nGp = ot.emd(a, b, Mp)\n\n# OT matrices\npl.figure(6, figsize=(7, 3))\n\npl.subplot(1, 3, 1)\not.plot.plot2D_samples_mat(xs, xt, G1, c=[.5, .5, 1])\npl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\npl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\npl.axis('equal')\n# pl.legend(loc=0)\npl.title('OT Euclidean')\n\npl.subplot(1, 3, 2)\not.plot.plot2D_samples_mat(xs, xt, G2, c=[.5, .5, 1])\npl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\npl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\npl.axis('equal')\n# pl.legend(loc=0)\npl.title('OT squared Euclidean')\n\npl.subplot(1, 3, 3)\not.plot.plot2D_samples_mat(xs, xt, Gp, c=[.5, .5, 1])\npl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\npl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples')\npl.axis('equal')\n# pl.legend(loc=0)\npl.title('OT sqrt Euclidean')\npl.tight_layout()\n\npl.show()" ], "outputs": [], "metadata": { diff --git a/docs/source/auto_examples/plot_OT_L1_vs_L2.py b/docs/source/auto_examples/plot_OT_L1_vs_L2.py index dfc9462..77bde22 100644 --- a/docs/source/auto_examples/plot_OT_L1_vs_L2.py +++ b/docs/source/auto_examples/plot_OT_L1_vs_L2.py @@ -4,6 +4,8 @@ 2D Optimal transport for different metrics ========================================== +2D OT on empirical distributio with different gound metric. + Stole the figure idea from Fig. 1 and 2 in https://arxiv.org/pdf/1706.07650.pdf @@ -18,98 +20,190 @@ import numpy as np import matplotlib.pylab as pl import ot -#%% parameters and data generation - -for data in range(2): - - if data: - n = 20 # nb samples - xs = np.zeros((n, 2)) - xs[:, 0] = np.arange(n) + 1 - xs[:, 1] = (np.arange(n) + 1) * -0.001 # to make it strictly convex... - - xt = np.zeros((n, 2)) - xt[:, 1] = np.arange(n) + 1 - else: - - n = 50 # nb samples - xtot = np.zeros((n + 1, 2)) - xtot[:, 0] = np.cos( - (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi) - xtot[:, 1] = np.sin( - (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi) - - xs = xtot[:n, :] - xt = xtot[1:, :] - - a, b = ot.unif(n), ot.unif(n) # uniform distribution on samples - - # loss matrix - M1 = ot.dist(xs, xt, metric='euclidean') - M1 /= M1.max() - - # loss matrix - M2 = ot.dist(xs, xt, metric='sqeuclidean') - M2 /= M2.max() - - # loss matrix - Mp = np.sqrt(ot.dist(xs, xt, metric='euclidean')) - Mp /= Mp.max() - - #%% plot samples - - pl.figure(1 + 3 * data, figsize=(7, 3)) - pl.clf() - pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') - pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') - pl.axis('equal') - pl.title('Source and traget distributions') - - pl.figure(2 + 3 * data, figsize=(7, 3)) - - pl.subplot(1, 3, 1) - pl.imshow(M1, interpolation='nearest') - pl.title('Euclidean cost') - - pl.subplot(1, 3, 2) - pl.imshow(M2, interpolation='nearest') - pl.title('Squared Euclidean cost') - - pl.subplot(1, 3, 3) - pl.imshow(Mp, interpolation='nearest') - pl.title('Sqrt Euclidean cost') - pl.tight_layout() - - #%% EMD - G1 = ot.emd(a, b, M1) - G2 = ot.emd(a, b, M2) - Gp = ot.emd(a, b, Mp) - - pl.figure(3 + 3 * data, figsize=(7, 3)) - - pl.subplot(1, 3, 1) - ot.plot.plot2D_samples_mat(xs, xt, G1, c=[.5, .5, 1]) - pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') - pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') - pl.axis('equal') - # pl.legend(loc=0) - pl.title('OT Euclidean') - - pl.subplot(1, 3, 2) - ot.plot.plot2D_samples_mat(xs, xt, G2, c=[.5, .5, 1]) - pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') - pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') - pl.axis('equal') - # pl.legend(loc=0) - pl.title('OT squared Euclidean') - - pl.subplot(1, 3, 3) - ot.plot.plot2D_samples_mat(xs, xt, Gp, c=[.5, .5, 1]) - pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') - pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') - pl.axis('equal') - # pl.legend(loc=0) - pl.title('OT sqrt Euclidean') - pl.tight_layout() +############################################################################## +# Dataset 1 : uniform sampling +############################################################################## + +n = 20 # nb samples +xs = np.zeros((n, 2)) +xs[:, 0] = np.arange(n) + 1 +xs[:, 1] = (np.arange(n) + 1) * -0.001 # to make it strictly convex... + +xt = np.zeros((n, 2)) +xt[:, 1] = np.arange(n) + 1 + +a, b = ot.unif(n), ot.unif(n) # uniform distribution on samples + +# loss matrix +M1 = ot.dist(xs, xt, metric='euclidean') +M1 /= M1.max() + +# loss matrix +M2 = ot.dist(xs, xt, metric='sqeuclidean') +M2 /= M2.max() + +# loss matrix +Mp = np.sqrt(ot.dist(xs, xt, metric='euclidean')) +Mp /= Mp.max() + +# Data +pl.figure(1, figsize=(7, 3)) +pl.clf() +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +pl.title('Source and traget distributions') + + +# Cost matrices +pl.figure(2, figsize=(7, 3)) + +pl.subplot(1, 3, 1) +pl.imshow(M1, interpolation='nearest') +pl.title('Euclidean cost') + +pl.subplot(1, 3, 2) +pl.imshow(M2, interpolation='nearest') +pl.title('Squared Euclidean cost') + +pl.subplot(1, 3, 3) +pl.imshow(Mp, interpolation='nearest') +pl.title('Sqrt Euclidean cost') +pl.tight_layout() + +############################################################################## +# Dataset 1 : Plot OT Matrices +############################################################################## + + + +#%% EMD +G1 = ot.emd(a, b, M1) +G2 = ot.emd(a, b, M2) +Gp = ot.emd(a, b, Mp) + +# OT matrices +pl.figure(3, figsize=(7, 3)) + +pl.subplot(1, 3, 1) +ot.plot.plot2D_samples_mat(xs, xt, G1, c=[.5, .5, 1]) +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +# pl.legend(loc=0) +pl.title('OT Euclidean') + +pl.subplot(1, 3, 2) +ot.plot.plot2D_samples_mat(xs, xt, G2, c=[.5, .5, 1]) +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +# pl.legend(loc=0) +pl.title('OT squared Euclidean') + +pl.subplot(1, 3, 3) +ot.plot.plot2D_samples_mat(xs, xt, Gp, c=[.5, .5, 1]) +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +# pl.legend(loc=0) +pl.title('OT sqrt Euclidean') +pl.tight_layout() + +pl.show() + + +############################################################################## +# Dataset 2 : Partial circle +############################################################################## + +n = 50 # nb samples +xtot = np.zeros((n + 1, 2)) +xtot[:, 0] = np.cos( + (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi) +xtot[:, 1] = np.sin( + (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi) + +xs = xtot[:n, :] +xt = xtot[1:, :] + +a, b = ot.unif(n), ot.unif(n) # uniform distribution on samples + +# loss matrix +M1 = ot.dist(xs, xt, metric='euclidean') +M1 /= M1.max() + +# loss matrix +M2 = ot.dist(xs, xt, metric='sqeuclidean') +M2 /= M2.max() + +# loss matrix +Mp = np.sqrt(ot.dist(xs, xt, metric='euclidean')) +Mp /= Mp.max() + + +# Data +pl.figure(4, figsize=(7, 3)) +pl.clf() +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +pl.title('Source and traget distributions') + + +# Cost matrices +pl.figure(5, figsize=(7, 3)) + +pl.subplot(1, 3, 1) +pl.imshow(M1, interpolation='nearest') +pl.title('Euclidean cost') + +pl.subplot(1, 3, 2) +pl.imshow(M2, interpolation='nearest') +pl.title('Squared Euclidean cost') + +pl.subplot(1, 3, 3) +pl.imshow(Mp, interpolation='nearest') +pl.title('Sqrt Euclidean cost') +pl.tight_layout() + +############################################################################## +# Dataset 2 : Plot OT Matrices +############################################################################## + + + +#%% EMD +G1 = ot.emd(a, b, M1) +G2 = ot.emd(a, b, M2) +Gp = ot.emd(a, b, Mp) + +# OT matrices +pl.figure(6, figsize=(7, 3)) + +pl.subplot(1, 3, 1) +ot.plot.plot2D_samples_mat(xs, xt, G1, c=[.5, .5, 1]) +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +# pl.legend(loc=0) +pl.title('OT Euclidean') + +pl.subplot(1, 3, 2) +ot.plot.plot2D_samples_mat(xs, xt, G2, c=[.5, .5, 1]) +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +# pl.legend(loc=0) +pl.title('OT squared Euclidean') + +pl.subplot(1, 3, 3) +ot.plot.plot2D_samples_mat(xs, xt, Gp, c=[.5, .5, 1]) +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +# pl.legend(loc=0) +pl.title('OT sqrt Euclidean') +pl.tight_layout() pl.show() diff --git a/docs/source/auto_examples/plot_OT_L1_vs_L2.rst b/docs/source/auto_examples/plot_OT_L1_vs_L2.rst index ba52bfe..83a7491 100644 --- a/docs/source/auto_examples/plot_OT_L1_vs_L2.rst +++ b/docs/source/auto_examples/plot_OT_L1_vs_L2.rst @@ -7,6 +7,8 @@ 2D Optimal transport for different metrics ========================================== +2D OT on empirical distributio with different gound metric. + Stole the figure idea from Fig. 1 and 2 in https://arxiv.org/pdf/1706.07650.pdf @@ -14,6 +16,80 @@ https://arxiv.org/pdf/1706.07650.pdf +.. code-block:: python + + + # Author: Remi Flamary + # + # License: MIT License + + import numpy as np + import matplotlib.pylab as pl + import ot + + + + + + + +Dataset 1 : uniform sampling +############################################################################# + + + +.. code-block:: python + + + n = 20 # nb samples + xs = np.zeros((n, 2)) + xs[:, 0] = np.arange(n) + 1 + xs[:, 1] = (np.arange(n) + 1) * -0.001 # to make it strictly convex... + + xt = np.zeros((n, 2)) + xt[:, 1] = np.arange(n) + 1 + + a, b = ot.unif(n), ot.unif(n) # uniform distribution on samples + + # loss matrix + M1 = ot.dist(xs, xt, metric='euclidean') + M1 /= M1.max() + + # loss matrix + M2 = ot.dist(xs, xt, metric='sqeuclidean') + M2 /= M2.max() + + # loss matrix + Mp = np.sqrt(ot.dist(xs, xt, metric='euclidean')) + Mp /= Mp.max() + + # Data + pl.figure(1, figsize=(7, 3)) + pl.clf() + pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') + pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') + pl.axis('equal') + pl.title('Source and traget distributions') + + + # Cost matrices + pl.figure(2, figsize=(7, 3)) + + pl.subplot(1, 3, 1) + pl.imshow(M1, interpolation='nearest') + pl.title('Euclidean cost') + + pl.subplot(1, 3, 2) + pl.imshow(M2, interpolation='nearest') + pl.title('Squared Euclidean cost') + + pl.subplot(1, 3, 3) + pl.imshow(Mp, interpolation='nearest') + pl.title('Sqrt Euclidean cost') + pl.tight_layout() + + + .. rst-class:: sphx-glr-horizontal @@ -28,138 +104,195 @@ https://arxiv.org/pdf/1706.07650.pdf .. image:: /auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_002.png :scale: 47 - * - .. image:: /auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_003.png - :scale: 47 - * - .. image:: /auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_004.png - :scale: 47 +Dataset 1 : Plot OT Matrices +############################################################################# + + + +.. code-block:: python + + + + + #%% EMD + G1 = ot.emd(a, b, M1) + G2 = ot.emd(a, b, M2) + Gp = ot.emd(a, b, Mp) + + # OT matrices + pl.figure(3, figsize=(7, 3)) + + pl.subplot(1, 3, 1) + ot.plot.plot2D_samples_mat(xs, xt, G1, c=[.5, .5, 1]) + pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') + pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') + pl.axis('equal') + # pl.legend(loc=0) + pl.title('OT Euclidean') + + pl.subplot(1, 3, 2) + ot.plot.plot2D_samples_mat(xs, xt, G2, c=[.5, .5, 1]) + pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') + pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') + pl.axis('equal') + # pl.legend(loc=0) + pl.title('OT squared Euclidean') + + pl.subplot(1, 3, 3) + ot.plot.plot2D_samples_mat(xs, xt, Gp, c=[.5, .5, 1]) + pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') + pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') + pl.axis('equal') + # pl.legend(loc=0) + pl.title('OT sqrt Euclidean') + pl.tight_layout() + + pl.show() + + + + + +.. image:: /auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_005.png + :align: center + + + + +Dataset 2 : Partial circle +############################################################################# + + + +.. code-block:: python + + + n = 50 # nb samples + xtot = np.zeros((n + 1, 2)) + xtot[:, 0] = np.cos( + (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi) + xtot[:, 1] = np.sin( + (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi) + + xs = xtot[:n, :] + xt = xtot[1:, :] + + a, b = ot.unif(n), ot.unif(n) # uniform distribution on samples + + # loss matrix + M1 = ot.dist(xs, xt, metric='euclidean') + M1 /= M1.max() + + # loss matrix + M2 = ot.dist(xs, xt, metric='sqeuclidean') + M2 /= M2.max() + + # loss matrix + Mp = np.sqrt(ot.dist(xs, xt, metric='euclidean')) + Mp /= Mp.max() + + + # Data + pl.figure(4, figsize=(7, 3)) + pl.clf() + pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') + pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') + pl.axis('equal') + pl.title('Source and traget distributions') + + + # Cost matrices + pl.figure(5, figsize=(7, 3)) + + pl.subplot(1, 3, 1) + pl.imshow(M1, interpolation='nearest') + pl.title('Euclidean cost') + + pl.subplot(1, 3, 2) + pl.imshow(M2, interpolation='nearest') + pl.title('Squared Euclidean cost') + + pl.subplot(1, 3, 3) + pl.imshow(Mp, interpolation='nearest') + pl.title('Sqrt Euclidean cost') + pl.tight_layout() + + + + +.. rst-class:: sphx-glr-horizontal + * - .. image:: /auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_005.png + .. image:: /auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_007.png :scale: 47 * - .. image:: /auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_006.png + .. image:: /auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_008.png :scale: 47 +Dataset 2 : Plot OT Matrices +############################################################################# + + .. code-block:: python - # Author: Remi Flamary - # - # License: MIT License - import numpy as np - import matplotlib.pylab as pl - import ot - #%% parameters and data generation - - for data in range(2): - - if data: - n = 20 # nb samples - xs = np.zeros((n, 2)) - xs[:, 0] = np.arange(n) + 1 - xs[:, 1] = (np.arange(n) + 1) * -0.001 # to make it strictly convex... - - xt = np.zeros((n, 2)) - xt[:, 1] = np.arange(n) + 1 - else: - - n = 50 # nb samples - xtot = np.zeros((n + 1, 2)) - xtot[:, 0] = np.cos( - (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi) - xtot[:, 1] = np.sin( - (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi) - - xs = xtot[:n, :] - xt = xtot[1:, :] - - a, b = ot.unif(n), ot.unif(n) # uniform distribution on samples - - # loss matrix - M1 = ot.dist(xs, xt, metric='euclidean') - M1 /= M1.max() - - # loss matrix - M2 = ot.dist(xs, xt, metric='sqeuclidean') - M2 /= M2.max() - - # loss matrix - Mp = np.sqrt(ot.dist(xs, xt, metric='euclidean')) - Mp /= Mp.max() - - #%% plot samples - - pl.figure(1 + 3 * data, figsize=(7, 3)) - pl.clf() - pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') - pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') - pl.axis('equal') - pl.title('Source and traget distributions') - - pl.figure(2 + 3 * data, figsize=(7, 3)) - - pl.subplot(1, 3, 1) - pl.imshow(M1, interpolation='nearest') - pl.title('Euclidean cost') - - pl.subplot(1, 3, 2) - pl.imshow(M2, interpolation='nearest') - pl.title('Squared Euclidean cost') - - pl.subplot(1, 3, 3) - pl.imshow(Mp, interpolation='nearest') - pl.title('Sqrt Euclidean cost') - pl.tight_layout() - - #%% EMD - G1 = ot.emd(a, b, M1) - G2 = ot.emd(a, b, M2) - Gp = ot.emd(a, b, Mp) - - pl.figure(3 + 3 * data, figsize=(7, 3)) - - pl.subplot(1, 3, 1) - ot.plot.plot2D_samples_mat(xs, xt, G1, c=[.5, .5, 1]) - pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') - pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') - pl.axis('equal') - # pl.legend(loc=0) - pl.title('OT Euclidean') - - pl.subplot(1, 3, 2) - ot.plot.plot2D_samples_mat(xs, xt, G2, c=[.5, .5, 1]) - pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') - pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') - pl.axis('equal') - # pl.legend(loc=0) - pl.title('OT squared Euclidean') - - pl.subplot(1, 3, 3) - ot.plot.plot2D_samples_mat(xs, xt, Gp, c=[.5, .5, 1]) - pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') - pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') - pl.axis('equal') - # pl.legend(loc=0) - pl.title('OT sqrt Euclidean') - pl.tight_layout() + #%% EMD + G1 = ot.emd(a, b, M1) + G2 = ot.emd(a, b, M2) + Gp = ot.emd(a, b, Mp) + + # OT matrices + pl.figure(6, figsize=(7, 3)) + + pl.subplot(1, 3, 1) + ot.plot.plot2D_samples_mat(xs, xt, G1, c=[.5, .5, 1]) + pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') + pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') + pl.axis('equal') + # pl.legend(loc=0) + pl.title('OT Euclidean') + + pl.subplot(1, 3, 2) + ot.plot.plot2D_samples_mat(xs, xt, G2, c=[.5, .5, 1]) + pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') + pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') + pl.axis('equal') + # pl.legend(loc=0) + pl.title('OT squared Euclidean') + + pl.subplot(1, 3, 3) + ot.plot.plot2D_samples_mat(xs, xt, Gp, c=[.5, .5, 1]) + pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') + pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') + pl.axis('equal') + # pl.legend(loc=0) + pl.title('OT sqrt Euclidean') + pl.tight_layout() pl.show() -**Total running time of the script:** ( 0 minutes 1.906 seconds) + + +.. image:: /auto_examples/images/sphx_glr_plot_OT_L1_vs_L2_011.png + :align: center + + + + +**Total running time of the script:** ( 0 minutes 1.217 seconds) @@ -178,4 +311,4 @@ https://arxiv.org/pdf/1706.07650.pdf .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_OT_conv.ipynb b/docs/source/auto_examples/plot_OT_conv.ipynb deleted file mode 100644 index 7fc4af0..0000000 --- a/docs/source/auto_examples/plot_OT_conv.ipynb +++ /dev/null @@ -1,54 +0,0 @@ -{ - "nbformat_minor": 0, - "nbformat": 4, - "cells": [ - { - "execution_count": null, - "cell_type": "code", - "source": [ - "%matplotlib inline" - ], - "outputs": [], - "metadata": { - "collapsed": false - } - }, - { - "source": [ - "\n# 1D Wasserstein barycenter demo\n\n\n\n@author: rflamary\n\n" - ], - "cell_type": "markdown", - "metadata": {} - }, - { - "execution_count": null, - "cell_type": "code", - "source": [ - "import numpy as np\nimport matplotlib.pylab as pl\nimport ot\nfrom mpl_toolkits.mplot3d import Axes3D #necessary for 3d plot even if not used\nimport scipy as sp\nimport scipy.signal as sps\n#%% parameters\n\nn=10 # nb bins\n\n# bin positions\nx=np.arange(n,dtype=np.float64)\n\nxx,yy=np.meshgrid(x,x)\n\n\nxpos=np.hstack((xx.reshape(-1,1),yy.reshape(-1,1)))\n\nM=ot.dist(xpos)\n\n\nI0=((xx-5)**2+(yy-5)**2<3**2)*1.0\nI1=((xx-7)**2+(yy-7)**2<3**2)*1.0\n\nI0/=I0.sum()\nI1/=I1.sum()\n\ni0=I0.ravel()\ni1=I1.ravel()\n\nM=M[i0>0,:][:,i1>0].copy()\ni0=i0[i0>0]\ni1=i1[i1>0]\nItot=np.concatenate((I0[:,:,np.newaxis],I1[:,:,np.newaxis]),2)\n\n\n#%% plot the distributions\n\npl.figure(1)\npl.subplot(2,2,1)\npl.imshow(I0)\npl.subplot(2,2,2)\npl.imshow(I1)\n\n\n#%% barycenter computation\n\nalpha=0.5 # 0<=alpha<=1\nweights=np.array([1-alpha,alpha])\n\n\ndef conv2(I,k):\n return sp.ndimage.convolve1d(sp.ndimage.convolve1d(I,k,axis=1),k,axis=0)\n\ndef conv2n(I,k):\n res=np.zeros_like(I)\n for i in range(I.shape[2]):\n res[:,:,i]=conv2(I[:,:,i],k)\n return res\n\n\ndef get_1Dkernel(reg,thr=1e-16,wmax=1024):\n w=max(min(wmax,2*int((-np.log(thr)*reg)**(.5))),3)\n x=np.arange(w,dtype=np.float64)\n return np.exp(-((x-w/2)**2)/reg)\n \nthr=1e-16\nreg=1e0\n\nk=get_1Dkernel(reg)\npl.figure(2)\npl.plot(k)\n\nI05=conv2(I0,k)\n\npl.figure(1)\npl.subplot(2,2,1)\npl.imshow(I0)\npl.subplot(2,2,2)\npl.imshow(I05)\n\n#%%\n\nG=ot.emd(i0,i1,M)\nr0=np.sum(M*G)\n\nreg=1e-1\nGs=ot.bregman.sinkhorn_knopp(i0,i1,M,reg=reg)\nrs=np.sum(M*Gs)\n\n#%%\n\ndef mylog(u):\n tmp=np.log(u)\n tmp[np.isnan(tmp)]=0\n return tmp\n\ndef sinkhorn_conv(a,b, reg, numItermax = 1000, stopThr=1e-9, verbose=False, log=False,**kwargs):\n\n\n a=np.asarray(a,dtype=np.float64)\n b=np.asarray(b,dtype=np.float64)\n \n \n if len(b.shape)>2:\n nbb=b.shape[2]\n a=a[:,:,np.newaxis]\n else:\n nbb=0\n \n\n if log:\n log={'err':[]}\n\n # we assume that no distances are null except those of the diagonal of distances\n if nbb:\n u = np.ones((a.shape[0],a.shape[1],nbb))/(np.prod(a.shape[:2]))\n v = np.ones((a.shape[0],a.shape[1],nbb))/(np.prod(b.shape[:2]))\n a0=1.0/(np.prod(b.shape[:2]))\n else:\n u = np.ones((a.shape[0],a.shape[1]))/(np.prod(a.shape[:2]))\n v = np.ones((a.shape[0],a.shape[1]))/(np.prod(b.shape[:2]))\n a0=1.0/(np.prod(b.shape[:2]))\n \n \n k=get_1Dkernel(reg)\n \n if nbb:\n K=lambda I: conv2n(I,k)\n else:\n K=lambda I: conv2(I,k)\n\n cpt = 0\n err=1\n while (err>stopThr and cpt0,:][:,i1>0].copy() -i0=i0[i0>0] -i1=i1[i1>0] -Itot=np.concatenate((I0[:,:,np.newaxis],I1[:,:,np.newaxis]),2) - - -#%% plot the distributions - -pl.figure(1) -pl.subplot(2,2,1) -pl.imshow(I0) -pl.subplot(2,2,2) -pl.imshow(I1) - - -#%% barycenter computation - -alpha=0.5 # 0<=alpha<=1 -weights=np.array([1-alpha,alpha]) - - -def conv2(I,k): - return sp.ndimage.convolve1d(sp.ndimage.convolve1d(I,k,axis=1),k,axis=0) - -def conv2n(I,k): - res=np.zeros_like(I) - for i in range(I.shape[2]): - res[:,:,i]=conv2(I[:,:,i],k) - return res - - -def get_1Dkernel(reg,thr=1e-16,wmax=1024): - w=max(min(wmax,2*int((-np.log(thr)*reg)**(.5))),3) - x=np.arange(w,dtype=np.float64) - return np.exp(-((x-w/2)**2)/reg) - -thr=1e-16 -reg=1e0 - -k=get_1Dkernel(reg) -pl.figure(2) -pl.plot(k) - -I05=conv2(I0,k) - -pl.figure(1) -pl.subplot(2,2,1) -pl.imshow(I0) -pl.subplot(2,2,2) -pl.imshow(I05) - -#%% - -G=ot.emd(i0,i1,M) -r0=np.sum(M*G) - -reg=1e-1 -Gs=ot.bregman.sinkhorn_knopp(i0,i1,M,reg=reg) -rs=np.sum(M*Gs) - -#%% - -def mylog(u): - tmp=np.log(u) - tmp[np.isnan(tmp)]=0 - return tmp - -def sinkhorn_conv(a,b, reg, numItermax = 1000, stopThr=1e-9, verbose=False, log=False,**kwargs): - - - a=np.asarray(a,dtype=np.float64) - b=np.asarray(b,dtype=np.float64) - - - if len(b.shape)>2: - nbb=b.shape[2] - a=a[:,:,np.newaxis] - else: - nbb=0 - - - if log: - log={'err':[]} - - # we assume that no distances are null except those of the diagonal of distances - if nbb: - u = np.ones((a.shape[0],a.shape[1],nbb))/(np.prod(a.shape[:2])) - v = np.ones((a.shape[0],a.shape[1],nbb))/(np.prod(b.shape[:2])) - a0=1.0/(np.prod(b.shape[:2])) - else: - u = np.ones((a.shape[0],a.shape[1]))/(np.prod(a.shape[:2])) - v = np.ones((a.shape[0],a.shape[1]))/(np.prod(b.shape[:2])) - a0=1.0/(np.prod(b.shape[:2])) - - - k=get_1Dkernel(reg) - - if nbb: - K=lambda I: conv2n(I,k) - else: - K=lambda I: conv2(I,k) - - cpt = 0 - err=1 - while (err>stopThr and cpt", line 86, in - TypeError: unsupported operand type(s) for *: 'float' and 'Mock' - - - - - -.. code-block:: python - - - import numpy as np - import matplotlib.pylab as pl - import ot - from mpl_toolkits.mplot3d import Axes3D #necessary for 3d plot even if not used - import scipy as sp - import scipy.signal as sps - #%% parameters - - n=10 # nb bins - - # bin positions - x=np.arange(n,dtype=np.float64) - - xx,yy=np.meshgrid(x,x) - - - xpos=np.hstack((xx.reshape(-1,1),yy.reshape(-1,1))) - - M=ot.dist(xpos) - - - I0=((xx-5)**2+(yy-5)**2<3**2)*1.0 - I1=((xx-7)**2+(yy-7)**2<3**2)*1.0 - - I0/=I0.sum() - I1/=I1.sum() - - i0=I0.ravel() - i1=I1.ravel() - - M=M[i0>0,:][:,i1>0].copy() - i0=i0[i0>0] - i1=i1[i1>0] - Itot=np.concatenate((I0[:,:,np.newaxis],I1[:,:,np.newaxis]),2) - - - #%% plot the distributions - - pl.figure(1) - pl.subplot(2,2,1) - pl.imshow(I0) - pl.subplot(2,2,2) - pl.imshow(I1) - - - #%% barycenter computation - - alpha=0.5 # 0<=alpha<=1 - weights=np.array([1-alpha,alpha]) - - - def conv2(I,k): - return sp.ndimage.convolve1d(sp.ndimage.convolve1d(I,k,axis=1),k,axis=0) - - def conv2n(I,k): - res=np.zeros_like(I) - for i in range(I.shape[2]): - res[:,:,i]=conv2(I[:,:,i],k) - return res - - - def get_1Dkernel(reg,thr=1e-16,wmax=1024): - w=max(min(wmax,2*int((-np.log(thr)*reg)**(.5))),3) - x=np.arange(w,dtype=np.float64) - return np.exp(-((x-w/2)**2)/reg) - - thr=1e-16 - reg=1e0 - - k=get_1Dkernel(reg) - pl.figure(2) - pl.plot(k) - - I05=conv2(I0,k) - - pl.figure(1) - pl.subplot(2,2,1) - pl.imshow(I0) - pl.subplot(2,2,2) - pl.imshow(I05) - - #%% - - G=ot.emd(i0,i1,M) - r0=np.sum(M*G) - - reg=1e-1 - Gs=ot.bregman.sinkhorn_knopp(i0,i1,M,reg=reg) - rs=np.sum(M*Gs) - - #%% - - def mylog(u): - tmp=np.log(u) - tmp[np.isnan(tmp)]=0 - return tmp - - def sinkhorn_conv(a,b, reg, numItermax = 1000, stopThr=1e-9, verbose=False, log=False,**kwargs): - - - a=np.asarray(a,dtype=np.float64) - b=np.asarray(b,dtype=np.float64) - - - if len(b.shape)>2: - nbb=b.shape[2] - a=a[:,:,np.newaxis] - else: - nbb=0 - - - if log: - log={'err':[]} - - # we assume that no distances are null except those of the diagonal of distances - if nbb: - u = np.ones((a.shape[0],a.shape[1],nbb))/(np.prod(a.shape[:2])) - v = np.ones((a.shape[0],a.shape[1],nbb))/(np.prod(b.shape[:2])) - a0=1.0/(np.prod(b.shape[:2])) - else: - u = np.ones((a.shape[0],a.shape[1]))/(np.prod(a.shape[:2])) - v = np.ones((a.shape[0],a.shape[1]))/(np.prod(b.shape[:2])) - a0=1.0/(np.prod(b.shape[:2])) - - - k=get_1Dkernel(reg) - - if nbb: - K=lambda I: conv2n(I,k) - else: - K=lambda I: conv2(I,k) - - cpt = 0 - err=1 - while (err>stopThr and cpt` - - - - .. container:: sphx-glr-download - - :download:`Download Jupyter notebook: plot_OT_conv.ipynb ` - -.. rst-class:: sphx-glr-signature - - `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_WDA.ipynb b/docs/source/auto_examples/plot_WDA.ipynb index 5568128..8e0db41 100644 --- a/docs/source/auto_examples/plot_WDA.ipynb +++ b/docs/source/auto_examples/plot_WDA.ipynb @@ -15,7 +15,7 @@ }, { "source": [ - "\n# Wasserstein Discriminant Analysis\n\n\n\n" + "\n# Wasserstein Discriminant Analysis\n\n\nThis example illustrate the use of WDA as proposed in [11].\n\n\n[11] Flamary, R., Cuturi, M., Courty, N., & Rakotomamonjy, A. (2016). \nWasserstein Discriminant Analysis.\n\n\n" ], "cell_type": "markdown", "metadata": {} @@ -24,7 +24,97 @@ "execution_count": null, "cell_type": "code", "source": [ - "# Author: Remi Flamary \n#\n# License: MIT License\n\nimport numpy as np\nimport matplotlib.pylab as pl\n\nfrom ot.dr import wda, fda\n\n\n#%% parameters\n\nn = 1000 # nb samples in source and target datasets\nnz = 0.2\n\n# generate circle dataset\nt = np.random.rand(n) * 2 * np.pi\nys = np.floor((np.arange(n) * 1.0 / n * 3)) + 1\nxs = np.concatenate(\n (np.cos(t).reshape((-1, 1)), np.sin(t).reshape((-1, 1))), 1)\nxs = xs * ys.reshape(-1, 1) + nz * np.random.randn(n, 2)\n\nt = np.random.rand(n) * 2 * np.pi\nyt = np.floor((np.arange(n) * 1.0 / n * 3)) + 1\nxt = np.concatenate(\n (np.cos(t).reshape((-1, 1)), np.sin(t).reshape((-1, 1))), 1)\nxt = xt * yt.reshape(-1, 1) + nz * np.random.randn(n, 2)\n\nnbnoise = 8\n\nxs = np.hstack((xs, np.random.randn(n, nbnoise)))\nxt = np.hstack((xt, np.random.randn(n, nbnoise)))\n\n#%% plot samples\npl.figure(1, figsize=(6.4, 3.5))\n\npl.subplot(1, 2, 1)\npl.scatter(xt[:, 0], xt[:, 1], c=ys, marker='+', label='Source samples')\npl.legend(loc=0)\npl.title('Discriminant dimensions')\n\npl.subplot(1, 2, 2)\npl.scatter(xt[:, 2], xt[:, 3], c=ys, marker='+', label='Source samples')\npl.legend(loc=0)\npl.title('Other dimensions')\npl.tight_layout()\n\n#%% Compute FDA\np = 2\n\nPfda, projfda = fda(xs, ys, p)\n\n#%% Compute WDA\np = 2\nreg = 1e0\nk = 10\nmaxiter = 100\n\nPwda, projwda = wda(xs, ys, p, reg, k, maxiter=maxiter)\n\n#%% plot samples\n\nxsp = projfda(xs)\nxtp = projfda(xt)\n\nxspw = projwda(xs)\nxtpw = projwda(xt)\n\npl.figure(2)\n\npl.subplot(2, 2, 1)\npl.scatter(xsp[:, 0], xsp[:, 1], c=ys, marker='+', label='Projected samples')\npl.legend(loc=0)\npl.title('Projected training samples FDA')\n\npl.subplot(2, 2, 2)\npl.scatter(xtp[:, 0], xtp[:, 1], c=ys, marker='+', label='Projected samples')\npl.legend(loc=0)\npl.title('Projected test samples FDA')\n\npl.subplot(2, 2, 3)\npl.scatter(xspw[:, 0], xspw[:, 1], c=ys, marker='+', label='Projected samples')\npl.legend(loc=0)\npl.title('Projected training samples WDA')\n\npl.subplot(2, 2, 4)\npl.scatter(xtpw[:, 0], xtpw[:, 1], c=ys, marker='+', label='Projected samples')\npl.legend(loc=0)\npl.title('Projected test samples WDA')\npl.tight_layout()\n\npl.show()" + "# Author: Remi Flamary \n#\n# License: MIT License\n\nimport numpy as np\nimport matplotlib.pylab as pl\n\nfrom ot.dr import wda, fda" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Generate data\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% parameters\n\nn = 1000 # nb samples in source and target datasets\nnz = 0.2\n\n# generate circle dataset\nt = np.random.rand(n) * 2 * np.pi\nys = np.floor((np.arange(n) * 1.0 / n * 3)) + 1\nxs = np.concatenate(\n (np.cos(t).reshape((-1, 1)), np.sin(t).reshape((-1, 1))), 1)\nxs = xs * ys.reshape(-1, 1) + nz * np.random.randn(n, 2)\n\nt = np.random.rand(n) * 2 * np.pi\nyt = np.floor((np.arange(n) * 1.0 / n * 3)) + 1\nxt = np.concatenate(\n (np.cos(t).reshape((-1, 1)), np.sin(t).reshape((-1, 1))), 1)\nxt = xt * yt.reshape(-1, 1) + nz * np.random.randn(n, 2)\n\nnbnoise = 8\n\nxs = np.hstack((xs, np.random.randn(n, nbnoise)))\nxt = np.hstack((xt, np.random.randn(n, nbnoise)))" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Plot data\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% plot samples\npl.figure(1, figsize=(6.4, 3.5))\n\npl.subplot(1, 2, 1)\npl.scatter(xt[:, 0], xt[:, 1], c=ys, marker='+', label='Source samples')\npl.legend(loc=0)\npl.title('Discriminant dimensions')\n\npl.subplot(1, 2, 2)\npl.scatter(xt[:, 2], xt[:, 3], c=ys, marker='+', label='Source samples')\npl.legend(loc=0)\npl.title('Other dimensions')\npl.tight_layout()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Compute Fisher Discriminant Analysis\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% Compute FDA\np = 2\n\nPfda, projfda = fda(xs, ys, p)" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Compute Wasserstein Discriminant Analysis\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% Compute WDA\np = 2\nreg = 1e0\nk = 10\nmaxiter = 100\n\nPwda, projwda = wda(xs, ys, p, reg, k, maxiter=maxiter)" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Plot 2D projections\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% plot samples\n\nxsp = projfda(xs)\nxtp = projfda(xt)\n\nxspw = projwda(xs)\nxtpw = projwda(xt)\n\npl.figure(2)\n\npl.subplot(2, 2, 1)\npl.scatter(xsp[:, 0], xsp[:, 1], c=ys, marker='+', label='Projected samples')\npl.legend(loc=0)\npl.title('Projected training samples FDA')\n\npl.subplot(2, 2, 2)\npl.scatter(xtp[:, 0], xtp[:, 1], c=ys, marker='+', label='Projected samples')\npl.legend(loc=0)\npl.title('Projected test samples FDA')\n\npl.subplot(2, 2, 3)\npl.scatter(xspw[:, 0], xspw[:, 1], c=ys, marker='+', label='Projected samples')\npl.legend(loc=0)\npl.title('Projected training samples WDA')\n\npl.subplot(2, 2, 4)\npl.scatter(xtpw[:, 0], xtpw[:, 1], c=ys, marker='+', label='Projected samples')\npl.legend(loc=0)\npl.title('Projected test samples WDA')\npl.tight_layout()\n\npl.show()" ], "outputs": [], "metadata": { diff --git a/docs/source/auto_examples/plot_WDA.py b/docs/source/auto_examples/plot_WDA.py index 42789f2..06a2e38 100644 --- a/docs/source/auto_examples/plot_WDA.py +++ b/docs/source/auto_examples/plot_WDA.py @@ -4,6 +4,12 @@ Wasserstein Discriminant Analysis ================================= +This example illustrate the use of WDA as proposed in [11]. + + +[11] Flamary, R., Cuturi, M., Courty, N., & Rakotomamonjy, A. (2016). +Wasserstein Discriminant Analysis. + """ # Author: Remi Flamary @@ -16,6 +22,10 @@ import matplotlib.pylab as pl from ot.dr import wda, fda +############################################################################## +# Generate data +############################################################################## + #%% parameters n = 1000 # nb samples in source and target datasets @@ -39,6 +49,10 @@ nbnoise = 8 xs = np.hstack((xs, np.random.randn(n, nbnoise))) xt = np.hstack((xt, np.random.randn(n, nbnoise))) +############################################################################## +# Plot data +############################################################################## + #%% plot samples pl.figure(1, figsize=(6.4, 3.5)) @@ -53,11 +67,19 @@ pl.legend(loc=0) pl.title('Other dimensions') pl.tight_layout() +############################################################################## +# Compute Fisher Discriminant Analysis +############################################################################## + #%% Compute FDA p = 2 Pfda, projfda = fda(xs, ys, p) +############################################################################## +# Compute Wasserstein Discriminant Analysis +############################################################################## + #%% Compute WDA p = 2 reg = 1e0 @@ -66,6 +88,11 @@ maxiter = 100 Pwda, projwda = wda(xs, ys, p, reg, k, maxiter=maxiter) + +############################################################################## +# Plot 2D projections +############################################################################## + #%% plot samples xsp = projfda(xs) diff --git a/docs/source/auto_examples/plot_WDA.rst b/docs/source/auto_examples/plot_WDA.rst index 76ebaf5..8c9ee29 100644 --- a/docs/source/auto_examples/plot_WDA.rst +++ b/docs/source/auto_examples/plot_WDA.rst @@ -7,86 +7,40 @@ Wasserstein Discriminant Analysis ================================= +This example illustrate the use of WDA as proposed in [11]. +[11] Flamary, R., Cuturi, M., Courty, N., & Rakotomamonjy, A. (2016). +Wasserstein Discriminant Analysis. -.. rst-class:: sphx-glr-horizontal - * +.. code-block:: python - .. image:: /auto_examples/images/sphx_glr_plot_WDA_001.png - :scale: 47 - * + # Author: Remi Flamary + # + # License: MIT License - .. image:: /auto_examples/images/sphx_glr_plot_WDA_002.png - :scale: 47 + import numpy as np + import matplotlib.pylab as pl + from ot.dr import wda, fda -.. rst-class:: sphx-glr-script-out - Out:: - Compiling cost function... - Computing gradient of cost function... - iter cost val grad. norm - 1 +8.9741888001949222e-01 3.71269078e-01 - 2 +4.9103998133976140e-01 3.46687543e-01 - 3 +4.2142651893148553e-01 1.04789602e-01 - 4 +4.1573609749588841e-01 5.21726648e-02 - 5 +4.1486046805261961e-01 5.35335513e-02 - 6 +4.1315953904635105e-01 2.17803599e-02 - 7 +4.1313030162717523e-01 6.06901182e-02 - 8 +4.1301511591963386e-01 5.88598758e-02 - 9 +4.1258349404769817e-01 5.14307874e-02 - 10 +4.1139242901051226e-01 2.03198793e-02 - 11 +4.1113798965164017e-01 1.18944721e-02 - 12 +4.1103446820878486e-01 2.21783648e-02 - 13 +4.1076586830791861e-01 9.51495863e-03 - 14 +4.1036935287519144e-01 3.74973214e-02 - 15 +4.0958729714575060e-01 1.23810902e-02 - 16 +4.0898266309095005e-01 4.01999918e-02 - 17 +4.0816076944357715e-01 2.27240277e-02 - 18 +4.0788116701894767e-01 4.42815945e-02 - 19 +4.0695443744952403e-01 3.28464304e-02 - 20 +4.0293834480911150e-01 7.76000681e-02 - 21 +3.8488003705202750e-01 1.49378022e-01 - 22 +3.0767344927282614e-01 2.15432117e-01 - 23 +2.3849425361868334e-01 1.07942382e-01 - 24 +2.3845125762548214e-01 1.08953278e-01 - 25 +2.3828007730494005e-01 1.07934830e-01 - 26 +2.3760839060570119e-01 1.03822134e-01 - 27 +2.3514215179705886e-01 8.67263481e-02 - 28 +2.2978886197588613e-01 9.26609306e-03 - 29 +2.2972671019495342e-01 2.59476089e-03 - 30 +2.2972355865247496e-01 1.57205146e-03 - 31 +2.2972296662351968e-01 1.29300760e-03 - 32 +2.2972181557051569e-01 8.82375756e-05 - 33 +2.2972181277025336e-01 6.20536544e-05 - 34 +2.2972181023486152e-01 7.01884014e-06 - 35 +2.2972181020400181e-01 1.60415765e-06 - 36 +2.2972181020236590e-01 2.44290966e-07 - Terminated - min grad norm reached after 36 iterations, 13.41 seconds. - - - - -| -.. code-block:: python - # Author: Remi Flamary - # - # License: MIT License - import numpy as np - import matplotlib.pylab as pl +Generate data +############################################################################# - from ot.dr import wda, fda + + +.. code-block:: python #%% parameters @@ -112,6 +66,20 @@ Wasserstein Discriminant Analysis xs = np.hstack((xs, np.random.randn(n, nbnoise))) xt = np.hstack((xt, np.random.randn(n, nbnoise))) + + + + + + +Plot data +############################################################################# + + + +.. code-block:: python + + #%% plot samples pl.figure(1, figsize=(6.4, 3.5)) @@ -126,11 +94,42 @@ Wasserstein Discriminant Analysis pl.title('Other dimensions') pl.tight_layout() + + + +.. image:: /auto_examples/images/sphx_glr_plot_WDA_001.png + :align: center + + + + +Compute Fisher Discriminant Analysis +############################################################################# + + + +.. code-block:: python + + #%% Compute FDA p = 2 Pfda, projfda = fda(xs, ys, p) + + + + + + +Compute Wasserstein Discriminant Analysis +############################################################################# + + + +.. code-block:: python + + #%% Compute WDA p = 2 reg = 1e0 @@ -139,6 +138,45 @@ Wasserstein Discriminant Analysis Pwda, projwda = wda(xs, ys, p, reg, k, maxiter=maxiter) + + + + + +.. rst-class:: sphx-glr-script-out + + Out:: + + Compiling cost function... + Computing gradient of cost function... + iter cost val grad. norm + 1 +7.7038877420882157e-01 6.30647522e-01 + 2 +3.3969600919721271e-01 2.83791849e-01 + 3 +3.0014000762425608e-01 2.56139137e-01 + 4 +2.3397191702411621e-01 6.41134216e-02 + 5 +2.3107227220070231e-01 2.24837190e-02 + 6 +2.3072327156158298e-01 1.71334761e-03 + 7 +2.3072143589220098e-01 6.30059431e-04 + 8 +2.3072133109125159e-01 4.88673790e-04 + 9 +2.3072119579341774e-01 1.74129117e-04 + 10 +2.3072118662364521e-01 1.27046386e-04 + 11 +2.3072118228917746e-01 9.70877451e-05 + 12 +2.3072117734120351e-01 4.17292699e-05 + 13 +2.3072117623493599e-01 4.46062100e-06 + 14 +2.3072117622383431e-01 1.59801454e-06 + 15 +2.3072117622300498e-01 1.12117391e-06 + 16 +2.3072117622220378e-01 4.14581994e-08 + Terminated - min grad norm reached after 16 iterations, 7.77 seconds. + + +Plot 2D projections +############################################################################# + + + +.. code-block:: python + + #%% plot samples xsp = projfda(xs) @@ -172,7 +210,15 @@ Wasserstein Discriminant Analysis pl.show() -**Total running time of the script:** ( 0 minutes 19.853 seconds) + + +.. image:: /auto_examples/images/sphx_glr_plot_WDA_003.png + :align: center + + + + +**Total running time of the script:** ( 0 minutes 8.568 seconds) @@ -191,4 +237,4 @@ Wasserstein Discriminant Analysis .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_barycenter_1D.ipynb b/docs/source/auto_examples/plot_barycenter_1D.ipynb index 239b8b8..657782d 100644 --- a/docs/source/auto_examples/plot_barycenter_1D.ipynb +++ b/docs/source/auto_examples/plot_barycenter_1D.ipynb @@ -15,7 +15,7 @@ }, { "source": [ - "\n# 1D Wasserstein barycenter demo\n\n\n\n" + "\n# 1D Wasserstein barycenter demo\n\n\nThis example illustrates the computation of regularized Wassersyein Barycenter \nas proposed in [3].\n\n\n[3] Benamou, J. D., Carlier, G., Cuturi, M., Nenna, L., & Peyr\u00e9, G. (2015). \nIterative Bregman projections for regularized transportation problems\nSIAM Journal on Scientific Computing, 37(2), A1111-A1138.\n\n\n" ], "cell_type": "markdown", "metadata": {} @@ -24,7 +24,79 @@ "execution_count": null, "cell_type": "code", "source": [ - "# Author: Remi Flamary \n#\n# License: MIT License\n\nimport numpy as np\nimport matplotlib.pylab as pl\nimport ot\n# necessary for 3d plot even if not used\nfrom mpl_toolkits.mplot3d import Axes3D # noqa\nfrom matplotlib.collections import PolyCollection\n\n\n#%% parameters\n\nn = 100 # nb bins\n\n# bin positions\nx = np.arange(n, dtype=np.float64)\n\n# Gaussian distributions\na1 = ot.datasets.get_1D_gauss(n, m=20, s=5) # m= mean, s= std\na2 = ot.datasets.get_1D_gauss(n, m=60, s=8)\n\n# creating matrix A containing all distributions\nA = np.vstack((a1, a2)).T\nn_distributions = A.shape[1]\n\n# loss matrix + normalization\nM = ot.utils.dist0(n)\nM /= M.max()\n\n#%% plot the distributions\n\npl.figure(1, figsize=(6.4, 3))\nfor i in range(n_distributions):\n pl.plot(x, A[:, i])\npl.title('Distributions')\npl.tight_layout()\n\n#%% barycenter computation\n\nalpha = 0.2 # 0<=alpha<=1\nweights = np.array([1 - alpha, alpha])\n\n# l2bary\nbary_l2 = A.dot(weights)\n\n# wasserstein\nreg = 1e-3\nbary_wass = ot.bregman.barycenter(A, M, reg, weights)\n\npl.figure(2)\npl.clf()\npl.subplot(2, 1, 1)\nfor i in range(n_distributions):\n pl.plot(x, A[:, i])\npl.title('Distributions')\n\npl.subplot(2, 1, 2)\npl.plot(x, bary_l2, 'r', label='l2')\npl.plot(x, bary_wass, 'g', label='Wasserstein')\npl.legend()\npl.title('Barycenters')\npl.tight_layout()\n\n#%% barycenter interpolation\n\nn_alpha = 11\nalpha_list = np.linspace(0, 1, n_alpha)\n\n\nB_l2 = np.zeros((n, n_alpha))\n\nB_wass = np.copy(B_l2)\n\nfor i in range(0, n_alpha):\n alpha = alpha_list[i]\n weights = np.array([1 - alpha, alpha])\n B_l2[:, i] = A.dot(weights)\n B_wass[:, i] = ot.bregman.barycenter(A, M, reg, weights)\n\n#%% plot interpolation\n\npl.figure(3)\n\ncmap = pl.cm.get_cmap('viridis')\nverts = []\nzs = alpha_list\nfor i, z in enumerate(zs):\n ys = B_l2[:, i]\n verts.append(list(zip(x, ys)))\n\nax = pl.gcf().gca(projection='3d')\n\npoly = PolyCollection(verts, facecolors=[cmap(a) for a in alpha_list])\npoly.set_alpha(0.7)\nax.add_collection3d(poly, zs=zs, zdir='y')\nax.set_xlabel('x')\nax.set_xlim3d(0, n)\nax.set_ylabel('$\\\\alpha$')\nax.set_ylim3d(0, 1)\nax.set_zlabel('')\nax.set_zlim3d(0, B_l2.max() * 1.01)\npl.title('Barycenter interpolation with l2')\npl.tight_layout()\n\npl.figure(4)\ncmap = pl.cm.get_cmap('viridis')\nverts = []\nzs = alpha_list\nfor i, z in enumerate(zs):\n ys = B_wass[:, i]\n verts.append(list(zip(x, ys)))\n\nax = pl.gcf().gca(projection='3d')\n\npoly = PolyCollection(verts, facecolors=[cmap(a) for a in alpha_list])\npoly.set_alpha(0.7)\nax.add_collection3d(poly, zs=zs, zdir='y')\nax.set_xlabel('x')\nax.set_xlim3d(0, n)\nax.set_ylabel('$\\\\alpha$')\nax.set_ylim3d(0, 1)\nax.set_zlabel('')\nax.set_zlim3d(0, B_l2.max() * 1.01)\npl.title('Barycenter interpolation with Wasserstein')\npl.tight_layout()\n\npl.show()" + "# Author: Remi Flamary \n#\n# License: MIT License\n\nimport numpy as np\nimport matplotlib.pylab as pl\nimport ot\n# necessary for 3d plot even if not used\nfrom mpl_toolkits.mplot3d import Axes3D # noqa\nfrom matplotlib.collections import PolyCollection" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Generate data\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% parameters\n\nn = 100 # nb bins\n\n# bin positions\nx = np.arange(n, dtype=np.float64)\n\n# Gaussian distributions\na1 = ot.datasets.get_1D_gauss(n, m=20, s=5) # m= mean, s= std\na2 = ot.datasets.get_1D_gauss(n, m=60, s=8)\n\n# creating matrix A containing all distributions\nA = np.vstack((a1, a2)).T\nn_distributions = A.shape[1]\n\n# loss matrix + normalization\nM = ot.utils.dist0(n)\nM /= M.max()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Plot data\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% plot the distributions\n\npl.figure(1, figsize=(6.4, 3))\nfor i in range(n_distributions):\n pl.plot(x, A[:, i])\npl.title('Distributions')\npl.tight_layout()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Barycenter computation\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% barycenter computation\n\nalpha = 0.2 # 0<=alpha<=1\nweights = np.array([1 - alpha, alpha])\n\n# l2bary\nbary_l2 = A.dot(weights)\n\n# wasserstein\nreg = 1e-3\nbary_wass = ot.bregman.barycenter(A, M, reg, weights)\n\npl.figure(2)\npl.clf()\npl.subplot(2, 1, 1)\nfor i in range(n_distributions):\n pl.plot(x, A[:, i])\npl.title('Distributions')\n\npl.subplot(2, 1, 2)\npl.plot(x, bary_l2, 'r', label='l2')\npl.plot(x, bary_wass, 'g', label='Wasserstein')\npl.legend()\npl.title('Barycenters')\npl.tight_layout()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Barycentric interpolation\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% barycenter interpolation\n\nn_alpha = 11\nalpha_list = np.linspace(0, 1, n_alpha)\n\n\nB_l2 = np.zeros((n, n_alpha))\n\nB_wass = np.copy(B_l2)\n\nfor i in range(0, n_alpha):\n alpha = alpha_list[i]\n weights = np.array([1 - alpha, alpha])\n B_l2[:, i] = A.dot(weights)\n B_wass[:, i] = ot.bregman.barycenter(A, M, reg, weights)\n\n#%% plot interpolation\n\npl.figure(3)\n\ncmap = pl.cm.get_cmap('viridis')\nverts = []\nzs = alpha_list\nfor i, z in enumerate(zs):\n ys = B_l2[:, i]\n verts.append(list(zip(x, ys)))\n\nax = pl.gcf().gca(projection='3d')\n\npoly = PolyCollection(verts, facecolors=[cmap(a) for a in alpha_list])\npoly.set_alpha(0.7)\nax.add_collection3d(poly, zs=zs, zdir='y')\nax.set_xlabel('x')\nax.set_xlim3d(0, n)\nax.set_ylabel('$\\\\alpha$')\nax.set_ylim3d(0, 1)\nax.set_zlabel('')\nax.set_zlim3d(0, B_l2.max() * 1.01)\npl.title('Barycenter interpolation with l2')\npl.tight_layout()\n\npl.figure(4)\ncmap = pl.cm.get_cmap('viridis')\nverts = []\nzs = alpha_list\nfor i, z in enumerate(zs):\n ys = B_wass[:, i]\n verts.append(list(zip(x, ys)))\n\nax = pl.gcf().gca(projection='3d')\n\npoly = PolyCollection(verts, facecolors=[cmap(a) for a in alpha_list])\npoly.set_alpha(0.7)\nax.add_collection3d(poly, zs=zs, zdir='y')\nax.set_xlabel('x')\nax.set_xlim3d(0, n)\nax.set_ylabel('$\\\\alpha$')\nax.set_ylim3d(0, 1)\nax.set_zlabel('')\nax.set_zlim3d(0, B_l2.max() * 1.01)\npl.title('Barycenter interpolation with Wasserstein')\npl.tight_layout()\n\npl.show()" ], "outputs": [], "metadata": { diff --git a/docs/source/auto_examples/plot_barycenter_1D.py b/docs/source/auto_examples/plot_barycenter_1D.py index 875f44c..142b05e 100644 --- a/docs/source/auto_examples/plot_barycenter_1D.py +++ b/docs/source/auto_examples/plot_barycenter_1D.py @@ -4,6 +4,14 @@ 1D Wasserstein barycenter demo ============================== +This example illustrates the computation of regularized Wassersyein Barycenter +as proposed in [3]. + + +[3] Benamou, J. D., Carlier, G., Cuturi, M., Nenna, L., & Peyré, G. (2015). +Iterative Bregman projections for regularized transportation problems +SIAM Journal on Scientific Computing, 37(2), A1111-A1138. + """ # Author: Remi Flamary @@ -17,6 +25,9 @@ import ot from mpl_toolkits.mplot3d import Axes3D # noqa from matplotlib.collections import PolyCollection +############################################################################## +# Generate data +############################################################################## #%% parameters @@ -37,6 +48,10 @@ n_distributions = A.shape[1] M = ot.utils.dist0(n) M /= M.max() +############################################################################## +# Plot data +############################################################################## + #%% plot the distributions pl.figure(1, figsize=(6.4, 3)) @@ -45,6 +60,10 @@ for i in range(n_distributions): pl.title('Distributions') pl.tight_layout() +############################################################################## +# Barycenter computation +############################################################################## + #%% barycenter computation alpha = 0.2 # 0<=alpha<=1 @@ -71,6 +90,10 @@ pl.legend() pl.title('Barycenters') pl.tight_layout() +############################################################################## +# Barycentric interpolation +############################################################################## + #%% barycenter interpolation n_alpha = 11 diff --git a/docs/source/auto_examples/plot_barycenter_1D.rst b/docs/source/auto_examples/plot_barycenter_1D.rst index af88e80..d3f243f 100644 --- a/docs/source/auto_examples/plot_barycenter_1D.rst +++ b/docs/source/auto_examples/plot_barycenter_1D.rst @@ -7,33 +7,13 @@ 1D Wasserstein barycenter demo ============================== +This example illustrates the computation of regularized Wassersyein Barycenter +as proposed in [3]. - - -.. rst-class:: sphx-glr-horizontal - - - * - - .. image:: /auto_examples/images/sphx_glr_plot_barycenter_1D_001.png - :scale: 47 - - * - - .. image:: /auto_examples/images/sphx_glr_plot_barycenter_1D_002.png - :scale: 47 - - * - - .. image:: /auto_examples/images/sphx_glr_plot_barycenter_1D_003.png - :scale: 47 - - * - - .. image:: /auto_examples/images/sphx_glr_plot_barycenter_1D_004.png - :scale: 47 - +[3] Benamou, J. D., Carlier, G., Cuturi, M., Nenna, L., & Peyré, G. (2015). +Iterative Bregman projections for regularized transportation problems +SIAM Journal on Scientific Computing, 37(2), A1111-A1138. @@ -53,6 +33,19 @@ from matplotlib.collections import PolyCollection + + + + + +Generate data +############################################################################# + + + +.. code-block:: python + + #%% parameters n = 100 # nb bins @@ -72,6 +65,20 @@ M = ot.utils.dist0(n) M /= M.max() + + + + + + +Plot data +############################################################################# + + + +.. code-block:: python + + #%% plot the distributions pl.figure(1, figsize=(6.4, 3)) @@ -80,6 +87,23 @@ pl.title('Distributions') pl.tight_layout() + + + +.. image:: /auto_examples/images/sphx_glr_plot_barycenter_1D_001.png + :align: center + + + + +Barycenter computation +############################################################################# + + + +.. code-block:: python + + #%% barycenter computation alpha = 0.2 # 0<=alpha<=1 @@ -106,6 +130,23 @@ pl.title('Barycenters') pl.tight_layout() + + + +.. image:: /auto_examples/images/sphx_glr_plot_barycenter_1D_003.png + :align: center + + + + +Barycentric interpolation +############################################################################# + + + +.. code-block:: python + + #%% barycenter interpolation n_alpha = 11 @@ -171,7 +212,25 @@ pl.show() -**Total running time of the script:** ( 0 minutes 0.546 seconds) + + +.. rst-class:: sphx-glr-horizontal + + + * + + .. image:: /auto_examples/images/sphx_glr_plot_barycenter_1D_005.png + :scale: 47 + + * + + .. image:: /auto_examples/images/sphx_glr_plot_barycenter_1D_006.png + :scale: 47 + + + + +**Total running time of the script:** ( 0 minutes 0.520 seconds) @@ -190,4 +249,4 @@ .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_compute_emd.ipynb b/docs/source/auto_examples/plot_compute_emd.ipynb index ce3f8c6..b28413b 100644 --- a/docs/source/auto_examples/plot_compute_emd.ipynb +++ b/docs/source/auto_examples/plot_compute_emd.ipynb @@ -15,7 +15,7 @@ }, { "source": [ - "\n# 1D optimal transport\n\n\n\n" + "\n# Plot multiple EMD\n\n\nShows how to compute multiple EMD and Sinkhorn with two differnt \nground metrics and plot their values for diffeent distributions.\n\n\n\n" ], "cell_type": "markdown", "metadata": {} @@ -24,7 +24,79 @@ "execution_count": null, "cell_type": "code", "source": [ - "# Author: Remi Flamary \n#\n# License: MIT License\n\nimport numpy as np\nimport matplotlib.pylab as pl\nimport ot\nfrom ot.datasets import get_1D_gauss as gauss\n\n\n#%% parameters\n\nn = 100 # nb bins\nn_target = 50 # nb target distributions\n\n\n# bin positions\nx = np.arange(n, dtype=np.float64)\n\nlst_m = np.linspace(20, 90, n_target)\n\n# Gaussian distributions\na = gauss(n, m=20, s=5) # m= mean, s= std\n\nB = np.zeros((n, n_target))\n\nfor i, m in enumerate(lst_m):\n B[:, i] = gauss(n, m=m, s=5)\n\n# loss matrix and normalization\nM = ot.dist(x.reshape((n, 1)), x.reshape((n, 1)), 'euclidean')\nM /= M.max()\nM2 = ot.dist(x.reshape((n, 1)), x.reshape((n, 1)), 'sqeuclidean')\nM2 /= M2.max()\n#%% plot the distributions\n\npl.figure(1)\npl.subplot(2, 1, 1)\npl.plot(x, a, 'b', label='Source distribution')\npl.title('Source distribution')\npl.subplot(2, 1, 2)\npl.plot(x, B, label='Target distributions')\npl.title('Target distributions')\npl.tight_layout()\n\n#%% Compute and plot distributions and loss matrix\n\nd_emd = ot.emd2(a, B, M) # direct computation of EMD\nd_emd2 = ot.emd2(a, B, M2) # direct computation of EMD with loss M3\n\n\npl.figure(2)\npl.plot(d_emd, label='Euclidean EMD')\npl.plot(d_emd2, label='Squared Euclidean EMD')\npl.title('EMD distances')\npl.legend()\n\n#%%\nreg = 1e-2\nd_sinkhorn = ot.sinkhorn2(a, B, M, reg)\nd_sinkhorn2 = ot.sinkhorn2(a, B, M2, reg)\n\npl.figure(2)\npl.clf()\npl.plot(d_emd, label='Euclidean EMD')\npl.plot(d_emd2, label='Squared Euclidean EMD')\npl.plot(d_sinkhorn, '+', label='Euclidean Sinkhorn')\npl.plot(d_sinkhorn2, '+', label='Squared Euclidean Sinkhorn')\npl.title('EMD distances')\npl.legend()\n\npl.show()" + "# Author: Remi Flamary \n#\n# License: MIT License\n\nimport numpy as np\nimport matplotlib.pylab as pl\nimport ot\nfrom ot.datasets import get_1D_gauss as gauss" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Generate data\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% parameters\n\nn = 100 # nb bins\nn_target = 50 # nb target distributions\n\n\n# bin positions\nx = np.arange(n, dtype=np.float64)\n\nlst_m = np.linspace(20, 90, n_target)\n\n# Gaussian distributions\na = gauss(n, m=20, s=5) # m= mean, s= std\n\nB = np.zeros((n, n_target))\n\nfor i, m in enumerate(lst_m):\n B[:, i] = gauss(n, m=m, s=5)\n\n# loss matrix and normalization\nM = ot.dist(x.reshape((n, 1)), x.reshape((n, 1)), 'euclidean')\nM /= M.max()\nM2 = ot.dist(x.reshape((n, 1)), x.reshape((n, 1)), 'sqeuclidean')\nM2 /= M2.max()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Plot data\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% plot the distributions\n\npl.figure(1)\npl.subplot(2, 1, 1)\npl.plot(x, a, 'b', label='Source distribution')\npl.title('Source distribution')\npl.subplot(2, 1, 2)\npl.plot(x, B, label='Target distributions')\npl.title('Target distributions')\npl.tight_layout()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Compute EMD for the different losses\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%% Compute and plot distributions and loss matrix\n\nd_emd = ot.emd2(a, B, M) # direct computation of EMD\nd_emd2 = ot.emd2(a, B, M2) # direct computation of EMD with loss M2\n\n\npl.figure(2)\npl.plot(d_emd, label='Euclidean EMD')\npl.plot(d_emd2, label='Squared Euclidean EMD')\npl.title('EMD distances')\npl.legend()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Compute Sinkhorn for the different losses\n#############################################################################\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "#%%\nreg = 1e-2\nd_sinkhorn = ot.sinkhorn2(a, B, M, reg)\nd_sinkhorn2 = ot.sinkhorn2(a, B, M2, reg)\n\npl.figure(2)\npl.clf()\npl.plot(d_emd, label='Euclidean EMD')\npl.plot(d_emd2, label='Squared Euclidean EMD')\npl.plot(d_sinkhorn, '+', label='Euclidean Sinkhorn')\npl.plot(d_sinkhorn2, '+', label='Squared Euclidean Sinkhorn')\npl.title('EMD distances')\npl.legend()\n\npl.show()" ], "outputs": [], "metadata": { diff --git a/docs/source/auto_examples/plot_compute_emd.py b/docs/source/auto_examples/plot_compute_emd.py index 893eecf..b688f93 100644 --- a/docs/source/auto_examples/plot_compute_emd.py +++ b/docs/source/auto_examples/plot_compute_emd.py @@ -1,8 +1,12 @@ # -*- coding: utf-8 -*- """ -==================== -1D optimal transport -==================== +================= +Plot multiple EMD +================= + +Shows how to compute multiple EMD and Sinkhorn with two differnt +ground metrics and plot their values for diffeent distributions. + """ @@ -16,6 +20,10 @@ import ot from ot.datasets import get_1D_gauss as gauss +############################################################################## +# Generate data +############################################################################## + #%% parameters n = 100 # nb bins @@ -40,6 +48,11 @@ M = ot.dist(x.reshape((n, 1)), x.reshape((n, 1)), 'euclidean') M /= M.max() M2 = ot.dist(x.reshape((n, 1)), x.reshape((n, 1)), 'sqeuclidean') M2 /= M2.max() + +############################################################################## +# Plot data +############################################################################## + #%% plot the distributions pl.figure(1) @@ -51,10 +64,15 @@ pl.plot(x, B, label='Target distributions') pl.title('Target distributions') pl.tight_layout() + +############################################################################## +# Compute EMD for the different losses +############################################################################## + #%% Compute and plot distributions and loss matrix d_emd = ot.emd2(a, B, M) # direct computation of EMD -d_emd2 = ot.emd2(a, B, M2) # direct computation of EMD with loss M3 +d_emd2 = ot.emd2(a, B, M2) # direct computation of EMD with loss M2 pl.figure(2) @@ -63,6 +81,10 @@ pl.plot(d_emd2, label='Squared Euclidean EMD') pl.title('EMD distances') pl.legend() +############################################################################## +# Compute Sinkhorn for the different losses +############################################################################## + #%% reg = 1e-2 d_sinkhorn = ot.sinkhorn2(a, B, M, reg) diff --git a/docs/source/auto_examples/plot_compute_emd.rst b/docs/source/auto_examples/plot_compute_emd.rst index f2e2005..b489255 100644 --- a/docs/source/auto_examples/plot_compute_emd.rst +++ b/docs/source/auto_examples/plot_compute_emd.rst @@ -3,42 +3,42 @@ .. _sphx_glr_auto_examples_plot_compute_emd.py: -==================== -1D optimal transport -==================== +================= +Plot multiple EMD +================= +Shows how to compute multiple EMD and Sinkhorn with two differnt +ground metrics and plot their values for diffeent distributions. -.. rst-class:: sphx-glr-horizontal +.. code-block:: python - * - .. image:: /auto_examples/images/sphx_glr_plot_compute_emd_001.png - :scale: 47 + # Author: Remi Flamary + # + # License: MIT License - * + import numpy as np + import matplotlib.pylab as pl + import ot + from ot.datasets import get_1D_gauss as gauss - .. image:: /auto_examples/images/sphx_glr_plot_compute_emd_002.png - :scale: 47 -.. code-block:: python - # Author: Remi Flamary - # - # License: MIT License +Generate data +############################################################################# - import numpy as np - import matplotlib.pylab as pl - import ot - from ot.datasets import get_1D_gauss as gauss + + +.. code-block:: python #%% parameters @@ -65,6 +65,21 @@ M /= M.max() M2 = ot.dist(x.reshape((n, 1)), x.reshape((n, 1)), 'sqeuclidean') M2 /= M2.max() + + + + + + + +Plot data +############################################################################# + + + +.. code-block:: python + + #%% plot the distributions pl.figure(1) @@ -76,10 +91,28 @@ pl.title('Target distributions') pl.tight_layout() + + + + +.. image:: /auto_examples/images/sphx_glr_plot_compute_emd_001.png + :align: center + + + + +Compute EMD for the different losses +############################################################################# + + + +.. code-block:: python + + #%% Compute and plot distributions and loss matrix d_emd = ot.emd2(a, B, M) # direct computation of EMD - d_emd2 = ot.emd2(a, B, M2) # direct computation of EMD with loss M3 + d_emd2 = ot.emd2(a, B, M2) # direct computation of EMD with loss M2 pl.figure(2) @@ -88,6 +121,23 @@ pl.title('EMD distances') pl.legend() + + + +.. image:: /auto_examples/images/sphx_glr_plot_compute_emd_003.png + :align: center + + + + +Compute Sinkhorn for the different losses +############################################################################# + + + +.. code-block:: python + + #%% reg = 1e-2 d_sinkhorn = ot.sinkhorn2(a, B, M, reg) @@ -104,7 +154,15 @@ pl.show() -**Total running time of the script:** ( 0 minutes 0.906 seconds) + + +.. image:: /auto_examples/images/sphx_glr_plot_compute_emd_004.png + :align: center + + + + +**Total running time of the script:** ( 0 minutes 0.427 seconds) @@ -123,4 +181,4 @@ .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_optim_OTreg.ipynb b/docs/source/auto_examples/plot_optim_OTreg.ipynb index 9d26e4d..290100f 100644 --- a/docs/source/auto_examples/plot_optim_OTreg.ipynb +++ b/docs/source/auto_examples/plot_optim_OTreg.ipynb @@ -15,7 +15,7 @@ }, { "source": [ - "\n# Regularized OT with generic solver\n\n\n\n\n" + "\n# Regularized OT with generic solver\n\n\nIllustrates the use of the generic solver for regularized OT with\nuser-designed regularization term. It uses Conditional gradient as in [6] and \ngeneralized Conditional Gradient as proposed in [5][7].\n\n\n[5] N. Courty; R. Flamary; D. Tuia; A. Rakotomamonjy, Optimal Transport for \nDomain Adaptation, in IEEE Transactions on Pattern Analysis and Machine \nIntelligence , vol.PP, no.99, pp.1-1.\n\n[6] Ferradans, S., Papadakis, N., Peyr\u00e9, G., & Aujol, J. F. (2014). \nRegularized discrete optimal transport. SIAM Journal on Imaging Sciences, \n7(3), 1853-1882.\n\n[7] Rakotomamonjy, A., Flamary, R., & Courty, N. (2015). Generalized \nconditional gradient: analysis of convergence and applications. \narXiv preprint arXiv:1510.06567.\n\n\n\n\n" ], "cell_type": "markdown", "metadata": {} @@ -33,7 +33,7 @@ }, { "source": [ - "Generate data \n#############################################################################\n\n" + "Generate data\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} @@ -51,7 +51,7 @@ }, { "source": [ - "Solve EMD \n#############################################################################\n\n" + "Solve EMD\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} @@ -114,7 +114,7 @@ "execution_count": null, "cell_type": "code", "source": [ - "#%% Example with Frobenius norm + entropic regularization with gcg\n\ndef f(G):\n return 0.5 * np.sum(G**2)\n\n\ndef df(G):\n return G\n\n\nreg1 = 1e-3\nreg2 = 1e-1\n\nGel2 = ot.optim.gcg(a, b, M, reg1, reg2, f, df, verbose=True)\n\npl.figure(5, figsize=(5, 5))\not.plot.plot1D_mat(a, b, Gel2, 'OT entropic + matrix Frob. reg')\npl.show()" + "#%% Example with Frobenius norm + entropic regularization with gcg\n\n\ndef f(G):\n return 0.5 * np.sum(G**2)\n\n\ndef df(G):\n return G\n\n\nreg1 = 1e-3\nreg2 = 1e-1\n\nGel2 = ot.optim.gcg(a, b, M, reg1, reg2, f, df, verbose=True)\n\npl.figure(5, figsize=(5, 5))\not.plot.plot1D_mat(a, b, Gel2, 'OT entropic + matrix Frob. reg')\npl.show()" ], "outputs": [], "metadata": { diff --git a/docs/source/auto_examples/plot_optim_OTreg.py b/docs/source/auto_examples/plot_optim_OTreg.py index d36b269..b362662 100644 --- a/docs/source/auto_examples/plot_optim_OTreg.py +++ b/docs/source/auto_examples/plot_optim_OTreg.py @@ -4,6 +4,24 @@ Regularized OT with generic solver ================================== +Illustrates the use of the generic solver for regularized OT with +user-designed regularization term. It uses Conditional gradient as in [6] and +generalized Conditional Gradient as proposed in [5][7]. + + +[5] N. Courty; R. Flamary; D. Tuia; A. Rakotomamonjy, Optimal Transport for +Domain Adaptation, in IEEE Transactions on Pattern Analysis and Machine +Intelligence , vol.PP, no.99, pp.1-1. + +[6] Ferradans, S., Papadakis, N., Peyré, G., & Aujol, J. F. (2014). +Regularized discrete optimal transport. SIAM Journal on Imaging Sciences, +7(3), 1853-1882. + +[7] Rakotomamonjy, A., Flamary, R., & Courty, N. (2015). Generalized +conditional gradient: analysis of convergence and applications. +arXiv preprint arXiv:1510.06567. + + """ @@ -13,7 +31,7 @@ import ot ############################################################################## -# Generate data +# Generate data ############################################################################## #%% parameters @@ -32,7 +50,7 @@ M = ot.dist(x.reshape((n, 1)), x.reshape((n, 1))) M /= M.max() ############################################################################## -# Solve EMD +# Solve EMD ############################################################################## #%% EMD @@ -92,6 +110,7 @@ ot.plot.plot1D_mat(a, b, Ge, 'OT matrix Entrop. reg') #%% Example with Frobenius norm + entropic regularization with gcg + def f(G): return 0.5 * np.sum(G**2) diff --git a/docs/source/auto_examples/plot_optim_OTreg.rst b/docs/source/auto_examples/plot_optim_OTreg.rst index 532d4ca..d444631 100644 --- a/docs/source/auto_examples/plot_optim_OTreg.rst +++ b/docs/source/auto_examples/plot_optim_OTreg.rst @@ -7,6 +7,24 @@ Regularized OT with generic solver ================================== +Illustrates the use of the generic solver for regularized OT with +user-designed regularization term. It uses Conditional gradient as in [6] and +generalized Conditional Gradient as proposed in [5][7]. + + +[5] N. Courty; R. Flamary; D. Tuia; A. Rakotomamonjy, Optimal Transport for +Domain Adaptation, in IEEE Transactions on Pattern Analysis and Machine +Intelligence , vol.PP, no.99, pp.1-1. + +[6] Ferradans, S., Papadakis, N., Peyré, G., & Aujol, J. F. (2014). +Regularized discrete optimal transport. SIAM Journal on Imaging Sciences, +7(3), 1853-1882. + +[7] Rakotomamonjy, A., Flamary, R., & Courty, N. (2015). Generalized +conditional gradient: analysis of convergence and applications. +arXiv preprint arXiv:1510.06567. + + @@ -25,7 +43,7 @@ Regularized OT with generic solver -Generate data +Generate data ############################################################################# @@ -54,7 +72,7 @@ Generate data -Solve EMD +Solve EMD ############################################################################# @@ -612,6 +630,7 @@ Solve EMD with Frobenius norm + entropic regularization #%% Example with Frobenius norm + entropic regularization with gcg + def f(G): return 0.5 * np.sum(G**2) @@ -645,10 +664,10 @@ Solve EMD with Frobenius norm + entropic regularization 1|1.610121e-01|-5.152589e-02 2|1.609378e-01|-4.622297e-04 3|1.609284e-01|-5.830043e-05 - 4|1.609284e-01|-1.111580e-12 + 4|1.609284e-01|-1.111407e-12 -**Total running time of the script:** ( 0 minutes 2.719 seconds) +**Total running time of the script:** ( 0 minutes 1.867 seconds) @@ -667,4 +686,4 @@ Solve EMD with Frobenius norm + entropic regularization .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_otda_classes.rst b/docs/source/auto_examples/plot_otda_classes.rst index 227a819..d1a13b1 100644 --- a/docs/source/auto_examples/plot_otda_classes.rst +++ b/docs/source/auto_examples/plot_otda_classes.rst @@ -94,29 +94,29 @@ Instantiate the different transport algorithms and fit them It. |Loss |Delta loss -------------------------------- - 0|9.456043e+00|0.000000e+00 - 1|2.059035e+00|-3.592463e+00 - 2|1.839814e+00|-1.191540e-01 - 3|1.787860e+00|-2.905942e-02 - 4|1.766582e+00|-1.204485e-02 - 5|1.760573e+00|-3.413038e-03 - 6|1.755288e+00|-3.010556e-03 - 7|1.749124e+00|-3.523968e-03 - 8|1.744159e+00|-2.846760e-03 - 9|1.741007e+00|-1.810862e-03 - 10|1.739839e+00|-6.710130e-04 - 11|1.737221e+00|-1.507260e-03 - 12|1.736011e+00|-6.970742e-04 - 13|1.734948e+00|-6.126425e-04 - 14|1.733901e+00|-6.038775e-04 - 15|1.733768e+00|-7.618542e-05 - 16|1.732821e+00|-5.467723e-04 - 17|1.732678e+00|-8.226843e-05 - 18|1.731934e+00|-4.300066e-04 - 19|1.731850e+00|-4.848002e-05 + 0|9.984935e+00|0.000000e+00 + 1|2.126803e+00|-3.694808e+00 + 2|1.867272e+00|-1.389895e-01 + 3|1.803858e+00|-3.515488e-02 + 4|1.783036e+00|-1.167761e-02 + 5|1.774823e+00|-4.627422e-03 + 6|1.771947e+00|-1.623526e-03 + 7|1.767564e+00|-2.479535e-03 + 8|1.763484e+00|-2.313667e-03 + 9|1.761138e+00|-1.331780e-03 + 10|1.758879e+00|-1.284576e-03 + 11|1.758034e+00|-4.806014e-04 + 12|1.757595e+00|-2.497155e-04 + 13|1.756749e+00|-4.818562e-04 + 14|1.755316e+00|-8.161432e-04 + 15|1.754988e+00|-1.866236e-04 + 16|1.754964e+00|-1.382474e-05 + 17|1.754032e+00|-5.315971e-04 + 18|1.753595e+00|-2.492359e-04 + 19|1.752900e+00|-3.961403e-04 It. |Loss |Delta loss -------------------------------- - 20|1.731699e+00|-8.729590e-05 + 20|1.752850e+00|-2.869262e-05 Fig 1 : plots source and target samples @@ -236,7 +236,7 @@ Fig 2 : plot optimal couplings and transported samples -**Total running time of the script:** ( 0 minutes 1.906 seconds) +**Total running time of the script:** ( 0 minutes 1.576 seconds) @@ -255,4 +255,4 @@ Fig 2 : plot optimal couplings and transported samples .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_otda_color_images.ipynb b/docs/source/auto_examples/plot_otda_color_images.ipynb index c45c307..797b27d 100644 --- a/docs/source/auto_examples/plot_otda_color_images.ipynb +++ b/docs/source/auto_examples/plot_otda_color_images.ipynb @@ -15,7 +15,7 @@ }, { "source": [ - "\n========================================================\nOT for domain adaptation with image color adaptation [6]\n========================================================\n\nThis example presents a way of transferring colors between two image\nwith Optimal Transport as introduced in [6]\n\n[6] Ferradans, S., Papadakis, N., Peyre, G., & Aujol, J. F. (2014).\nRegularized discrete optimal transport.\nSIAM Journal on Imaging Sciences, 7(3), 1853-1882.\n\n" + "\n# OT for image color adaptation\n\n\nThis example presents a way of transferring colors between two image\nwith Optimal Transport as introduced in [6]\n\n[6] Ferradans, S., Papadakis, N., Peyre, G., & Aujol, J. F. (2014).\nRegularized discrete optimal transport.\nSIAM Journal on Imaging Sciences, 7(3), 1853-1882.\n\n" ], "cell_type": "markdown", "metadata": {} @@ -33,7 +33,7 @@ }, { "source": [ - "generate data\n#############################################################################\n\n" + "Generate data\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} @@ -51,7 +51,7 @@ }, { "source": [ - "Instantiate the different transport algorithms and fit them\n#############################################################################\n\n" + "Plot original image\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} @@ -60,7 +60,7 @@ "execution_count": null, "cell_type": "code", "source": [ - "# EMDTransport\not_emd = ot.da.EMDTransport()\not_emd.fit(Xs=Xs, Xt=Xt)\n\n# SinkhornTransport\not_sinkhorn = ot.da.SinkhornTransport(reg_e=1e-1)\not_sinkhorn.fit(Xs=Xs, Xt=Xt)\n\n# prediction between images (using out of sample prediction as in [6])\ntransp_Xs_emd = ot_emd.transform(Xs=X1)\ntransp_Xt_emd = ot_emd.inverse_transform(Xt=X2)\n\ntransp_Xs_sinkhorn = ot_emd.transform(Xs=X1)\ntransp_Xt_sinkhorn = ot_emd.inverse_transform(Xt=X2)\n\nI1t = minmax(mat2im(transp_Xs_emd, I1.shape))\nI2t = minmax(mat2im(transp_Xt_emd, I2.shape))\n\nI1te = minmax(mat2im(transp_Xs_sinkhorn, I1.shape))\nI2te = minmax(mat2im(transp_Xt_sinkhorn, I2.shape))" + "pl.figure(1, figsize=(6.4, 3))\n\npl.subplot(1, 2, 1)\npl.imshow(I1)\npl.axis('off')\npl.title('Image 1')\n\npl.subplot(1, 2, 2)\npl.imshow(I2)\npl.axis('off')\npl.title('Image 2')" ], "outputs": [], "metadata": { @@ -69,7 +69,7 @@ }, { "source": [ - "plot original image\n#############################################################################\n\n" + "Scatter plot of colors\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} @@ -78,7 +78,7 @@ "execution_count": null, "cell_type": "code", "source": [ - "pl.figure(1, figsize=(6.4, 3))\n\npl.subplot(1, 2, 1)\npl.imshow(I1)\npl.axis('off')\npl.title('Image 1')\n\npl.subplot(1, 2, 2)\npl.imshow(I2)\npl.axis('off')\npl.title('Image 2')" + "pl.figure(2, figsize=(6.4, 3))\n\npl.subplot(1, 2, 1)\npl.scatter(Xs[:, 0], Xs[:, 2], c=Xs)\npl.axis([0, 1, 0, 1])\npl.xlabel('Red')\npl.ylabel('Blue')\npl.title('Image 1')\n\npl.subplot(1, 2, 2)\npl.scatter(Xt[:, 0], Xt[:, 2], c=Xt)\npl.axis([0, 1, 0, 1])\npl.xlabel('Red')\npl.ylabel('Blue')\npl.title('Image 2')\npl.tight_layout()" ], "outputs": [], "metadata": { @@ -87,7 +87,7 @@ }, { "source": [ - "scatter plot of colors\n#############################################################################\n\n" + "Instantiate the different transport algorithms and fit them\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} @@ -96,7 +96,7 @@ "execution_count": null, "cell_type": "code", "source": [ - "pl.figure(2, figsize=(6.4, 3))\n\npl.subplot(1, 2, 1)\npl.scatter(Xs[:, 0], Xs[:, 2], c=Xs)\npl.axis([0, 1, 0, 1])\npl.xlabel('Red')\npl.ylabel('Blue')\npl.title('Image 1')\n\npl.subplot(1, 2, 2)\npl.scatter(Xt[:, 0], Xt[:, 2], c=Xt)\npl.axis([0, 1, 0, 1])\npl.xlabel('Red')\npl.ylabel('Blue')\npl.title('Image 2')\npl.tight_layout()" + "# EMDTransport\not_emd = ot.da.EMDTransport()\not_emd.fit(Xs=Xs, Xt=Xt)\n\n# SinkhornTransport\not_sinkhorn = ot.da.SinkhornTransport(reg_e=1e-1)\not_sinkhorn.fit(Xs=Xs, Xt=Xt)\n\n# prediction between images (using out of sample prediction as in [6])\ntransp_Xs_emd = ot_emd.transform(Xs=X1)\ntransp_Xt_emd = ot_emd.inverse_transform(Xt=X2)\n\ntransp_Xs_sinkhorn = ot_emd.transform(Xs=X1)\ntransp_Xt_sinkhorn = ot_emd.inverse_transform(Xt=X2)\n\nI1t = minmax(mat2im(transp_Xs_emd, I1.shape))\nI2t = minmax(mat2im(transp_Xt_emd, I2.shape))\n\nI1te = minmax(mat2im(transp_Xs_sinkhorn, I1.shape))\nI2te = minmax(mat2im(transp_Xt_sinkhorn, I2.shape))" ], "outputs": [], "metadata": { @@ -105,7 +105,7 @@ }, { "source": [ - "plot new images\n#############################################################################\n\n" + "Plot new images\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_otda_color_images.py b/docs/source/auto_examples/plot_otda_color_images.py index 46ad44b..f1df9d9 100644 --- a/docs/source/auto_examples/plot_otda_color_images.py +++ b/docs/source/auto_examples/plot_otda_color_images.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- """ -======================================================== -OT for domain adaptation with image color adaptation [6] -======================================================== +============================= +OT for image color adaptation +============================= This example presents a way of transferring colors between two image with Optimal Transport as introduced in [6] @@ -41,7 +41,7 @@ def minmax(I): ############################################################################## -# generate data +# Generate data ############################################################################## # Loading images @@ -61,33 +61,7 @@ Xt = X2[idx2, :] ############################################################################## -# Instantiate the different transport algorithms and fit them -############################################################################## - -# EMDTransport -ot_emd = ot.da.EMDTransport() -ot_emd.fit(Xs=Xs, Xt=Xt) - -# SinkhornTransport -ot_sinkhorn = ot.da.SinkhornTransport(reg_e=1e-1) -ot_sinkhorn.fit(Xs=Xs, Xt=Xt) - -# prediction between images (using out of sample prediction as in [6]) -transp_Xs_emd = ot_emd.transform(Xs=X1) -transp_Xt_emd = ot_emd.inverse_transform(Xt=X2) - -transp_Xs_sinkhorn = ot_emd.transform(Xs=X1) -transp_Xt_sinkhorn = ot_emd.inverse_transform(Xt=X2) - -I1t = minmax(mat2im(transp_Xs_emd, I1.shape)) -I2t = minmax(mat2im(transp_Xt_emd, I2.shape)) - -I1te = minmax(mat2im(transp_Xs_sinkhorn, I1.shape)) -I2te = minmax(mat2im(transp_Xt_sinkhorn, I2.shape)) - - -############################################################################## -# plot original image +# Plot original image ############################################################################## pl.figure(1, figsize=(6.4, 3)) @@ -104,7 +78,7 @@ pl.title('Image 2') ############################################################################## -# scatter plot of colors +# Scatter plot of colors ############################################################################## pl.figure(2, figsize=(6.4, 3)) @@ -126,7 +100,33 @@ pl.tight_layout() ############################################################################## -# plot new images +# Instantiate the different transport algorithms and fit them +############################################################################## + +# EMDTransport +ot_emd = ot.da.EMDTransport() +ot_emd.fit(Xs=Xs, Xt=Xt) + +# SinkhornTransport +ot_sinkhorn = ot.da.SinkhornTransport(reg_e=1e-1) +ot_sinkhorn.fit(Xs=Xs, Xt=Xt) + +# prediction between images (using out of sample prediction as in [6]) +transp_Xs_emd = ot_emd.transform(Xs=X1) +transp_Xt_emd = ot_emd.inverse_transform(Xt=X2) + +transp_Xs_sinkhorn = ot_emd.transform(Xs=X1) +transp_Xt_sinkhorn = ot_emd.inverse_transform(Xt=X2) + +I1t = minmax(mat2im(transp_Xs_emd, I1.shape)) +I2t = minmax(mat2im(transp_Xt_emd, I2.shape)) + +I1te = minmax(mat2im(transp_Xs_sinkhorn, I1.shape)) +I2te = minmax(mat2im(transp_Xt_sinkhorn, I2.shape)) + + +############################################################################## +# Plot new images ############################################################################## pl.figure(3, figsize=(8, 4)) diff --git a/docs/source/auto_examples/plot_otda_color_images.rst b/docs/source/auto_examples/plot_otda_color_images.rst index e3989c8..88e93d2 100644 --- a/docs/source/auto_examples/plot_otda_color_images.rst +++ b/docs/source/auto_examples/plot_otda_color_images.rst @@ -3,9 +3,9 @@ .. _sphx_glr_auto_examples_plot_otda_color_images.py: -======================================================== -OT for domain adaptation with image color adaptation [6] -======================================================== +============================= +OT for image color adaptation +============================= This example presents a way of transferring colors between two image with Optimal Transport as introduced in [6] @@ -53,7 +53,7 @@ SIAM Journal on Imaging Sciences, 7(3), 1853-1882. -generate data +Generate data ############################################################################# @@ -83,43 +83,7 @@ generate data -Instantiate the different transport algorithms and fit them -############################################################################# - - - -.. code-block:: python - - - # EMDTransport - ot_emd = ot.da.EMDTransport() - ot_emd.fit(Xs=Xs, Xt=Xt) - - # SinkhornTransport - ot_sinkhorn = ot.da.SinkhornTransport(reg_e=1e-1) - ot_sinkhorn.fit(Xs=Xs, Xt=Xt) - - # prediction between images (using out of sample prediction as in [6]) - transp_Xs_emd = ot_emd.transform(Xs=X1) - transp_Xt_emd = ot_emd.inverse_transform(Xt=X2) - - transp_Xs_sinkhorn = ot_emd.transform(Xs=X1) - transp_Xt_sinkhorn = ot_emd.inverse_transform(Xt=X2) - - I1t = minmax(mat2im(transp_Xs_emd, I1.shape)) - I2t = minmax(mat2im(transp_Xt_emd, I2.shape)) - - I1te = minmax(mat2im(transp_Xs_sinkhorn, I1.shape)) - I2te = minmax(mat2im(transp_Xt_sinkhorn, I2.shape)) - - - - - - - - -plot original image +Plot original image ############################################################################# @@ -149,7 +113,7 @@ plot original image -scatter plot of colors +Scatter plot of colors ############################################################################# @@ -184,7 +148,43 @@ scatter plot of colors -plot new images +Instantiate the different transport algorithms and fit them +############################################################################# + + + +.. code-block:: python + + + # EMDTransport + ot_emd = ot.da.EMDTransport() + ot_emd.fit(Xs=Xs, Xt=Xt) + + # SinkhornTransport + ot_sinkhorn = ot.da.SinkhornTransport(reg_e=1e-1) + ot_sinkhorn.fit(Xs=Xs, Xt=Xt) + + # prediction between images (using out of sample prediction as in [6]) + transp_Xs_emd = ot_emd.transform(Xs=X1) + transp_Xt_emd = ot_emd.inverse_transform(Xt=X2) + + transp_Xs_sinkhorn = ot_emd.transform(Xs=X1) + transp_Xt_sinkhorn = ot_emd.inverse_transform(Xt=X2) + + I1t = minmax(mat2im(transp_Xs_emd, I1.shape)) + I2t = minmax(mat2im(transp_Xt_emd, I2.shape)) + + I1te = minmax(mat2im(transp_Xs_sinkhorn, I1.shape)) + I2te = minmax(mat2im(transp_Xt_sinkhorn, I2.shape)) + + + + + + + + +Plot new images ############################################################################# @@ -235,7 +235,7 @@ plot new images -**Total running time of the script:** ( 3 minutes 16.043 seconds) +**Total running time of the script:** ( 2 minutes 28.053 seconds) @@ -254,4 +254,4 @@ plot new images .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_otda_d2.rst b/docs/source/auto_examples/plot_otda_d2.rst index 20b76ba..3aa1149 100644 --- a/docs/source/auto_examples/plot_otda_d2.rst +++ b/docs/source/auto_examples/plot_otda_d2.rst @@ -243,7 +243,7 @@ Fig 3 : plot transported samples -**Total running time of the script:** ( 0 minutes 46.009 seconds) +**Total running time of the script:** ( 0 minutes 32.275 seconds) @@ -262,4 +262,4 @@ Fig 3 : plot transported samples .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_otda_mapping.ipynb b/docs/source/auto_examples/plot_otda_mapping.ipynb index 0b5ca5c..5b3fd06 100644 --- a/docs/source/auto_examples/plot_otda_mapping.ipynb +++ b/docs/source/auto_examples/plot_otda_mapping.ipynb @@ -15,7 +15,7 @@ }, { "source": [ - "\n===============================================\nOT mapping estimation for domain adaptation [8]\n===============================================\n\nThis example presents how to use MappingTransport to estimate at the same\ntime both the coupling transport and approximate the transport map with either\na linear or a kernelized mapping as introduced in [8]\n\n[8] M. Perrot, N. Courty, R. Flamary, A. Habrard,\n \"Mapping estimation for discrete optimal transport\",\n Neural Information Processing Systems (NIPS), 2016.\n\n" + "\n# OT mapping estimation for domain adaptation\n\n\nThis example presents how to use MappingTransport to estimate at the same\ntime both the coupling transport and approximate the transport map with either\na linear or a kernelized mapping as introduced in [8].\n\n[8] M. Perrot, N. Courty, R. Flamary, A. Habrard,\n \"Mapping estimation for discrete optimal transport\",\n Neural Information Processing Systems (NIPS), 2016.\n\n" ], "cell_type": "markdown", "metadata": {} @@ -33,7 +33,7 @@ }, { "source": [ - "generate data\n#############################################################################\n\n" + "Generate data\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} @@ -51,7 +51,7 @@ }, { "source": [ - "Instantiate the different transport algorithms and fit them\n#############################################################################\n\n" + "Plot data\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} @@ -60,7 +60,7 @@ "execution_count": null, "cell_type": "code", "source": [ - "# MappingTransport with linear kernel\not_mapping_linear = ot.da.MappingTransport(\n kernel=\"linear\", mu=1e0, eta=1e-8, bias=True,\n max_iter=20, verbose=True)\n\not_mapping_linear.fit(Xs=Xs, Xt=Xt)\n\n# for original source samples, transform applies barycentric mapping\ntransp_Xs_linear = ot_mapping_linear.transform(Xs=Xs)\n\n# for out of source samples, transform applies the linear mapping\ntransp_Xs_linear_new = ot_mapping_linear.transform(Xs=Xs_new)\n\n\n# MappingTransport with gaussian kernel\not_mapping_gaussian = ot.da.MappingTransport(\n kernel=\"gaussian\", eta=1e-5, mu=1e-1, bias=True, sigma=1,\n max_iter=10, verbose=True)\not_mapping_gaussian.fit(Xs=Xs, Xt=Xt)\n\n# for original source samples, transform applies barycentric mapping\ntransp_Xs_gaussian = ot_mapping_gaussian.transform(Xs=Xs)\n\n# for out of source samples, transform applies the gaussian mapping\ntransp_Xs_gaussian_new = ot_mapping_gaussian.transform(Xs=Xs_new)" + "pl.figure(1, (10, 5))\npl.clf()\npl.scatter(Xs[:, 0], Xs[:, 1], c=ys, marker='+', label='Source samples')\npl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', label='Target samples')\npl.legend(loc=0)\npl.title('Source and target distributions')" ], "outputs": [], "metadata": { @@ -69,7 +69,7 @@ }, { "source": [ - "plot data\n#############################################################################\n\n" + "Instantiate the different transport algorithms and fit them\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} @@ -78,7 +78,7 @@ "execution_count": null, "cell_type": "code", "source": [ - "pl.figure(1, (10, 5))\npl.clf()\npl.scatter(Xs[:, 0], Xs[:, 1], c=ys, marker='+', label='Source samples')\npl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', label='Target samples')\npl.legend(loc=0)\npl.title('Source and target distributions')" + "# MappingTransport with linear kernel\not_mapping_linear = ot.da.MappingTransport(\n kernel=\"linear\", mu=1e0, eta=1e-8, bias=True,\n max_iter=20, verbose=True)\n\not_mapping_linear.fit(Xs=Xs, Xt=Xt)\n\n# for original source samples, transform applies barycentric mapping\ntransp_Xs_linear = ot_mapping_linear.transform(Xs=Xs)\n\n# for out of source samples, transform applies the linear mapping\ntransp_Xs_linear_new = ot_mapping_linear.transform(Xs=Xs_new)\n\n\n# MappingTransport with gaussian kernel\not_mapping_gaussian = ot.da.MappingTransport(\n kernel=\"gaussian\", eta=1e-5, mu=1e-1, bias=True, sigma=1,\n max_iter=10, verbose=True)\not_mapping_gaussian.fit(Xs=Xs, Xt=Xt)\n\n# for original source samples, transform applies barycentric mapping\ntransp_Xs_gaussian = ot_mapping_gaussian.transform(Xs=Xs)\n\n# for out of source samples, transform applies the gaussian mapping\ntransp_Xs_gaussian_new = ot_mapping_gaussian.transform(Xs=Xs_new)" ], "outputs": [], "metadata": { @@ -87,7 +87,7 @@ }, { "source": [ - "plot transported samples\n#############################################################################\n\n" + "Plot transported samples\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_otda_mapping.py b/docs/source/auto_examples/plot_otda_mapping.py index 09d2cb4..e78fef4 100644 --- a/docs/source/auto_examples/plot_otda_mapping.py +++ b/docs/source/auto_examples/plot_otda_mapping.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ -=============================================== -OT mapping estimation for domain adaptation [8] -=============================================== +=========================================== +OT mapping estimation for domain adaptation +=========================================== This example presents how to use MappingTransport to estimate at the same time both the coupling transport and approximate the transport map with either -a linear or a kernelized mapping as introduced in [8] +a linear or a kernelized mapping as introduced in [8]. [8] M. Perrot, N. Courty, R. Flamary, A. Habrard, "Mapping estimation for discrete optimal transport", @@ -24,7 +24,7 @@ import ot ############################################################################## -# generate data +# Generate data ############################################################################## n_source_samples = 100 @@ -43,6 +43,17 @@ Xt, yt = ot.datasets.get_data_classif( Xt[yt == 2] *= 3 Xt = Xt + 4 +############################################################################## +# Plot data +############################################################################## + +pl.figure(1, (10, 5)) +pl.clf() +pl.scatter(Xs[:, 0], Xs[:, 1], c=ys, marker='+', label='Source samples') +pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', label='Target samples') +pl.legend(loc=0) +pl.title('Source and target distributions') + ############################################################################## # Instantiate the different transport algorithms and fit them @@ -76,19 +87,7 @@ transp_Xs_gaussian_new = ot_mapping_gaussian.transform(Xs=Xs_new) ############################################################################## -# plot data -############################################################################## - -pl.figure(1, (10, 5)) -pl.clf() -pl.scatter(Xs[:, 0], Xs[:, 1], c=ys, marker='+', label='Source samples') -pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', label='Target samples') -pl.legend(loc=0) -pl.title('Source and target distributions') - - -############################################################################## -# plot transported samples +# Plot transported samples ############################################################################## pl.figure(2) diff --git a/docs/source/auto_examples/plot_otda_mapping.rst b/docs/source/auto_examples/plot_otda_mapping.rst index 088da31..ddc1ee9 100644 --- a/docs/source/auto_examples/plot_otda_mapping.rst +++ b/docs/source/auto_examples/plot_otda_mapping.rst @@ -3,13 +3,13 @@ .. _sphx_glr_auto_examples_plot_otda_mapping.py: -=============================================== -OT mapping estimation for domain adaptation [8] -=============================================== +=========================================== +OT mapping estimation for domain adaptation +=========================================== This example presents how to use MappingTransport to estimate at the same time both the coupling transport and approximate the transport map with either -a linear or a kernelized mapping as introduced in [8] +a linear or a kernelized mapping as introduced in [8]. [8] M. Perrot, N. Courty, R. Flamary, A. Habrard, "Mapping estimation for discrete optimal transport", @@ -36,7 +36,7 @@ a linear or a kernelized mapping as introduced in [8] -generate data +Generate data ############################################################################# @@ -66,6 +66,30 @@ generate data +Plot data +############################################################################# + + + +.. code-block:: python + + + pl.figure(1, (10, 5)) + pl.clf() + pl.scatter(Xs[:, 0], Xs[:, 1], c=ys, marker='+', label='Source samples') + pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', label='Target samples') + pl.legend(loc=0) + pl.title('Source and target distributions') + + + + + +.. image:: /auto_examples/images/sphx_glr_plot_otda_mapping_001.png + :align: center + + + Instantiate the different transport algorithms and fit them ############################################################################# @@ -112,54 +136,29 @@ Instantiate the different transport algorithms and fit them It. |Loss |Delta loss -------------------------------- - 0|4.273804e+03|0.000000e+00 - 1|4.264510e+03|-2.174580e-03 - 2|4.264209e+03|-7.047095e-05 - 3|4.264078e+03|-3.069822e-05 - 4|4.264018e+03|-1.412924e-05 - 5|4.263961e+03|-1.341165e-05 - 6|4.263946e+03|-3.586522e-06 + 0|4.481482e+03|0.000000e+00 + 1|4.469389e+03|-2.698549e-03 + 2|4.468825e+03|-1.261217e-04 + 3|4.468580e+03|-5.486064e-05 + 4|4.468438e+03|-3.161220e-05 + 5|4.468352e+03|-1.930800e-05 + 6|4.468309e+03|-9.570658e-06 It. |Loss |Delta loss -------------------------------- - 0|4.294523e+02|0.000000e+00 - 1|4.247737e+02|-1.089443e-02 - 2|4.245516e+02|-5.228765e-04 - 3|4.244430e+02|-2.557417e-04 - 4|4.243724e+02|-1.663904e-04 - 5|4.243196e+02|-1.244111e-04 - 6|4.242808e+02|-9.132500e-05 - 7|4.242497e+02|-7.331710e-05 - 8|4.242271e+02|-5.326612e-05 - 9|4.242063e+02|-4.916026e-05 - 10|4.241906e+02|-3.699617e-05 - - -plot data -############################################################################# - - - -.. code-block:: python - - - pl.figure(1, (10, 5)) - pl.clf() - pl.scatter(Xs[:, 0], Xs[:, 1], c=ys, marker='+', label='Source samples') - pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', label='Target samples') - pl.legend(loc=0) - pl.title('Source and target distributions') - - - - - -.. image:: /auto_examples/images/sphx_glr_plot_otda_mapping_001.png - :align: center - - - - -plot transported samples + 0|4.504654e+02|0.000000e+00 + 1|4.461571e+02|-9.564116e-03 + 2|4.459105e+02|-5.528043e-04 + 3|4.457895e+02|-2.712398e-04 + 4|4.457041e+02|-1.914829e-04 + 5|4.456431e+02|-1.369704e-04 + 6|4.456032e+02|-8.944784e-05 + 7|4.455700e+02|-7.447824e-05 + 8|4.455447e+02|-5.688965e-05 + 9|4.455229e+02|-4.890051e-05 + 10|4.455084e+02|-3.262490e-05 + + +Plot transported samples ############################################################################# @@ -209,7 +208,7 @@ plot transported samples -**Total running time of the script:** ( 0 minutes 0.853 seconds) +**Total running time of the script:** ( 0 minutes 0.869 seconds) @@ -228,4 +227,4 @@ plot transported samples .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_otda_mapping_colors_images.ipynb b/docs/source/auto_examples/plot_otda_mapping_colors_images.ipynb index 4b2ec02..c8c1d95 100644 --- a/docs/source/auto_examples/plot_otda_mapping_colors_images.ipynb +++ b/docs/source/auto_examples/plot_otda_mapping_colors_images.ipynb @@ -15,7 +15,7 @@ }, { "source": [ - "\n====================================================================================\nOT for domain adaptation with image color adaptation [6] with mapping estimation [8]\n====================================================================================\n\n[6] Ferradans, S., Papadakis, N., Peyre, G., & Aujol, J. F. (2014). Regularized\n discrete optimal transport. SIAM Journal on Imaging Sciences, 7(3),\n 1853-1882.\n[8] M. Perrot, N. Courty, R. Flamary, A. Habrard, \"Mapping estimation for\n discrete optimal transport\", Neural Information Processing Systems (NIPS),\n 2016.\n\n\n" + "\n# OT for image color adaptation with mapping estimation \n\n\nOT for domain adaptation with image color adaptation [6] with mapping \nestimation [8].\n\n[6] Ferradans, S., Papadakis, N., Peyre, G., & Aujol, J. F. (2014). Regularized\n discrete optimal transport. SIAM Journal on Imaging Sciences, 7(3),\n 1853-1882.\n[8] M. Perrot, N. Courty, R. Flamary, A. Habrard, \"Mapping estimation for\n discrete optimal transport\", Neural Information Processing Systems (NIPS),\n 2016.\n\n\n" ], "cell_type": "markdown", "metadata": {} @@ -69,7 +69,7 @@ }, { "source": [ - "plot original images\n#############################################################################\n\n" + "Plot original images\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} @@ -87,7 +87,7 @@ }, { "source": [ - "plot pixel values distribution\n#############################################################################\n\n" + "Plot pixel values distribution\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} @@ -105,7 +105,7 @@ }, { "source": [ - "plot transformed images\n#############################################################################\n\n" + "Plot transformed images\n#############################################################################\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_otda_mapping_colors_images.py b/docs/source/auto_examples/plot_otda_mapping_colors_images.py index 936206c..162c24b 100644 --- a/docs/source/auto_examples/plot_otda_mapping_colors_images.py +++ b/docs/source/auto_examples/plot_otda_mapping_colors_images.py @@ -1,8 +1,11 @@ # -*- coding: utf-8 -*- """ -==================================================================================== -OT for domain adaptation with image color adaptation [6] with mapping estimation [8] -==================================================================================== +===================================================== +OT for image color adaptation with mapping estimation +===================================================== + +OT for domain adaptation with image color adaptation [6] with mapping +estimation [8]. [6] Ferradans, S., Papadakis, N., Peyre, G., & Aujol, J. F. (2014). Regularized discrete optimal transport. SIAM Journal on Imaging Sciences, 7(3), @@ -93,7 +96,7 @@ Image_mapping_gaussian = minmax(mat2im(X1tn, I1.shape)) ############################################################################## -# plot original images +# Plot original images ############################################################################## pl.figure(1, figsize=(6.4, 3)) @@ -110,7 +113,7 @@ pl.tight_layout() ############################################################################## -# plot pixel values distribution +# Plot pixel values distribution ############################################################################## pl.figure(2, figsize=(6.4, 5)) @@ -132,7 +135,7 @@ pl.tight_layout() ############################################################################## -# plot transformed images +# Plot transformed images ############################################################################## pl.figure(2, figsize=(10, 5)) diff --git a/docs/source/auto_examples/plot_otda_mapping_colors_images.rst b/docs/source/auto_examples/plot_otda_mapping_colors_images.rst index 1107067..29823f1 100644 --- a/docs/source/auto_examples/plot_otda_mapping_colors_images.rst +++ b/docs/source/auto_examples/plot_otda_mapping_colors_images.rst @@ -3,9 +3,12 @@ .. _sphx_glr_auto_examples_plot_otda_mapping_colors_images.py: -==================================================================================== -OT for domain adaptation with image color adaptation [6] with mapping estimation [8] -==================================================================================== +===================================================== +OT for image color adaptation with mapping estimation +===================================================== + +OT for domain adaptation with image color adaptation [6] with mapping +estimation [8]. [6] Ferradans, S., Papadakis, N., Peyre, G., & Aujol, J. F. (2014). Regularized discrete optimal transport. SIAM Journal on Imaging Sciences, 7(3), @@ -129,42 +132,42 @@ Domain adaptation for pixel distribution transfer It. |Loss |Delta loss -------------------------------- - 0|3.680514e+02|0.000000e+00 - 1|3.592359e+02|-2.395185e-02 - 2|3.590581e+02|-4.947749e-04 - 3|3.589663e+02|-2.556471e-04 - 4|3.589095e+02|-1.582289e-04 - 5|3.588707e+02|-1.081994e-04 - 6|3.588423e+02|-7.911661e-05 - 7|3.588206e+02|-6.055473e-05 - 8|3.588034e+02|-4.778202e-05 - 9|3.587895e+02|-3.886420e-05 - 10|3.587781e+02|-3.182249e-05 - 11|3.587684e+02|-2.695669e-05 - 12|3.587602e+02|-2.298642e-05 - 13|3.587530e+02|-1.993240e-05 - 14|3.587468e+02|-1.736014e-05 - 15|3.587413e+02|-1.518037e-05 - 16|3.587365e+02|-1.358038e-05 - 17|3.587321e+02|-1.215346e-05 - 18|3.587282e+02|-1.091639e-05 - 19|3.587278e+02|-9.877929e-07 + 0|3.680512e+02|0.000000e+00 + 1|3.592454e+02|-2.392562e-02 + 2|3.590671e+02|-4.960473e-04 + 3|3.589736e+02|-2.604894e-04 + 4|3.589161e+02|-1.602816e-04 + 5|3.588766e+02|-1.099971e-04 + 6|3.588476e+02|-8.084400e-05 + 7|3.588256e+02|-6.131161e-05 + 8|3.588083e+02|-4.807549e-05 + 9|3.587943e+02|-3.899414e-05 + 10|3.587827e+02|-3.245280e-05 + 11|3.587729e+02|-2.721256e-05 + 12|3.587646e+02|-2.316249e-05 + 13|3.587574e+02|-2.000192e-05 + 14|3.587512e+02|-1.748898e-05 + 15|3.587457e+02|-1.535131e-05 + 16|3.587408e+02|-1.366515e-05 + 17|3.587364e+02|-1.210563e-05 + 18|3.587325e+02|-1.097138e-05 + 19|3.587310e+02|-4.099596e-06 It. |Loss |Delta loss -------------------------------- - 0|3.784725e+02|0.000000e+00 - 1|3.646380e+02|-3.655332e-02 - 2|3.642858e+02|-9.660434e-04 - 3|3.641516e+02|-3.683776e-04 - 4|3.640785e+02|-2.008220e-04 - 5|3.640320e+02|-1.276966e-04 - 6|3.639999e+02|-8.796173e-05 - 7|3.639764e+02|-6.455658e-05 - 8|3.639583e+02|-4.976436e-05 - 9|3.639440e+02|-3.946556e-05 - 10|3.639322e+02|-3.222132e-05 - - -plot original images + 0|3.784805e+02|0.000000e+00 + 1|3.646476e+02|-3.654847e-02 + 2|3.642970e+02|-9.615381e-04 + 3|3.641622e+02|-3.699897e-04 + 4|3.640886e+02|-2.021154e-04 + 5|3.640419e+02|-1.280913e-04 + 6|3.640096e+02|-8.898145e-05 + 7|3.639858e+02|-6.514301e-05 + 8|3.639677e+02|-4.977195e-05 + 9|3.639534e+02|-3.936050e-05 + 10|3.639417e+02|-3.205223e-05 + + +Plot original images ############################################################################# @@ -194,7 +197,7 @@ plot original images -plot pixel values distribution +Plot pixel values distribution ############################################################################# @@ -229,7 +232,7 @@ plot pixel values distribution -plot transformed images +Plot transformed images ############################################################################# @@ -280,7 +283,7 @@ plot transformed images -**Total running time of the script:** ( 2 minutes 45.618 seconds) +**Total running time of the script:** ( 2 minutes 12.535 seconds) @@ -299,4 +302,4 @@ plot transformed images .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/conf.py b/docs/source/conf.py index ffdb1a2..0a822e5 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -33,7 +33,7 @@ class Mock(MagicMock): return MagicMock() MOCK_MODULES = ['ot.lp.emd_wrap','autograd','pymanopt','cudamat','autograd.numpy','pymanopt.manifolds','pymanopt.solvers'] # 'autograd.numpy','pymanopt.manifolds','pymanopt.solvers', -sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES) +##sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES) # !!!! # If extensions (or modules to document with autodoc) are in another directory, @@ -328,7 +328,7 @@ intersphinx_mapping = {'https://docs.python.org/': None} sphinx_gallery_conf = { 'examples_dirs': ['../../examples','../../examples/da'], 'gallery_dirs': 'auto_examples', - 'mod_example_dir': '../modules/generated/', + 'backreferences_dir': '../modules/generated/', 'reference_url': { 'numpy': 'http://docs.scipy.org/doc/numpy-1.9.1', 'scipy': 'http://docs.scipy.org/doc/scipy-0.17.0/reference'} diff --git a/docs/source/examples.rst b/docs/source/examples.rst deleted file mode 100644 index f209543..0000000 --- a/docs/source/examples.rst +++ /dev/null @@ -1,39 +0,0 @@ - - -Examples -============ - -1D Optimal transport ---------------------- - -.. literalinclude:: ../../examples/demo_OT_1D.py - -2D Optimal transport on empirical distributions ------------------------------------------------ - -.. literalinclude:: ../../examples/demo_OT_2D_samples.py - -1D Wasserstein barycenter -------------------------- - -.. literalinclude:: ../../examples/demo_barycenter_1D.py - -OT with user provided regularization ------------------------------------- - -.. literalinclude:: ../../examples/demo_optim_OTreg.py - -Domain adaptation with optimal transport ----------------------------------------- - -.. literalinclude:: ../../examples/demo_OTDA_classes.py - -Color transfer in images ------------------------- - -.. literalinclude:: ../../examples/demo_OTDA_color_images.py - -OT mapping estimation for domain adaptation -------------------------------------------- - -.. literalinclude:: ../../examples/demo_OTDA_mapping.py diff --git a/examples/README.txt b/examples/README.txt index f8643b8..c3d556d 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -1,2 +1,4 @@ POT Examples ============ + +This is a gallery of all the POT example files. diff --git a/examples/plot_OT_1D.py b/examples/plot_OT_1D.py index a1473c4..a63f29a 100644 --- a/examples/plot_OT_1D.py +++ b/examples/plot_OT_1D.py @@ -4,7 +4,7 @@ 1D optimal transport ==================== -This example illustrate the computation of EMD and Sinkhorn transport plans +This example illustrates the computation of EMD and Sinkhorn transport plans and their visualization. """ diff --git a/examples/plot_OT_2D_samples.py b/examples/plot_OT_2D_samples.py index a913b8c..f57d631 100644 --- a/examples/plot_OT_2D_samples.py +++ b/examples/plot_OT_2D_samples.py @@ -4,6 +4,9 @@ 2D Optimal transport between empirical distributions ==================================================== +Illustration of 2D optimal transport between discributions that are weighted +sum of diracs. The OT matrix is plotted with the samples. + """ # Author: Remi Flamary diff --git a/examples/plot_OT_L1_vs_L2.py b/examples/plot_OT_L1_vs_L2.py index dfc9462..77bde22 100644 --- a/examples/plot_OT_L1_vs_L2.py +++ b/examples/plot_OT_L1_vs_L2.py @@ -4,6 +4,8 @@ 2D Optimal transport for different metrics ========================================== +2D OT on empirical distributio with different gound metric. + Stole the figure idea from Fig. 1 and 2 in https://arxiv.org/pdf/1706.07650.pdf @@ -18,98 +20,190 @@ import numpy as np import matplotlib.pylab as pl import ot -#%% parameters and data generation - -for data in range(2): - - if data: - n = 20 # nb samples - xs = np.zeros((n, 2)) - xs[:, 0] = np.arange(n) + 1 - xs[:, 1] = (np.arange(n) + 1) * -0.001 # to make it strictly convex... - - xt = np.zeros((n, 2)) - xt[:, 1] = np.arange(n) + 1 - else: - - n = 50 # nb samples - xtot = np.zeros((n + 1, 2)) - xtot[:, 0] = np.cos( - (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi) - xtot[:, 1] = np.sin( - (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi) - - xs = xtot[:n, :] - xt = xtot[1:, :] - - a, b = ot.unif(n), ot.unif(n) # uniform distribution on samples - - # loss matrix - M1 = ot.dist(xs, xt, metric='euclidean') - M1 /= M1.max() - - # loss matrix - M2 = ot.dist(xs, xt, metric='sqeuclidean') - M2 /= M2.max() - - # loss matrix - Mp = np.sqrt(ot.dist(xs, xt, metric='euclidean')) - Mp /= Mp.max() - - #%% plot samples - - pl.figure(1 + 3 * data, figsize=(7, 3)) - pl.clf() - pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') - pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') - pl.axis('equal') - pl.title('Source and traget distributions') - - pl.figure(2 + 3 * data, figsize=(7, 3)) - - pl.subplot(1, 3, 1) - pl.imshow(M1, interpolation='nearest') - pl.title('Euclidean cost') - - pl.subplot(1, 3, 2) - pl.imshow(M2, interpolation='nearest') - pl.title('Squared Euclidean cost') - - pl.subplot(1, 3, 3) - pl.imshow(Mp, interpolation='nearest') - pl.title('Sqrt Euclidean cost') - pl.tight_layout() - - #%% EMD - G1 = ot.emd(a, b, M1) - G2 = ot.emd(a, b, M2) - Gp = ot.emd(a, b, Mp) - - pl.figure(3 + 3 * data, figsize=(7, 3)) - - pl.subplot(1, 3, 1) - ot.plot.plot2D_samples_mat(xs, xt, G1, c=[.5, .5, 1]) - pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') - pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') - pl.axis('equal') - # pl.legend(loc=0) - pl.title('OT Euclidean') - - pl.subplot(1, 3, 2) - ot.plot.plot2D_samples_mat(xs, xt, G2, c=[.5, .5, 1]) - pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') - pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') - pl.axis('equal') - # pl.legend(loc=0) - pl.title('OT squared Euclidean') - - pl.subplot(1, 3, 3) - ot.plot.plot2D_samples_mat(xs, xt, Gp, c=[.5, .5, 1]) - pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') - pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') - pl.axis('equal') - # pl.legend(loc=0) - pl.title('OT sqrt Euclidean') - pl.tight_layout() +############################################################################## +# Dataset 1 : uniform sampling +############################################################################## + +n = 20 # nb samples +xs = np.zeros((n, 2)) +xs[:, 0] = np.arange(n) + 1 +xs[:, 1] = (np.arange(n) + 1) * -0.001 # to make it strictly convex... + +xt = np.zeros((n, 2)) +xt[:, 1] = np.arange(n) + 1 + +a, b = ot.unif(n), ot.unif(n) # uniform distribution on samples + +# loss matrix +M1 = ot.dist(xs, xt, metric='euclidean') +M1 /= M1.max() + +# loss matrix +M2 = ot.dist(xs, xt, metric='sqeuclidean') +M2 /= M2.max() + +# loss matrix +Mp = np.sqrt(ot.dist(xs, xt, metric='euclidean')) +Mp /= Mp.max() + +# Data +pl.figure(1, figsize=(7, 3)) +pl.clf() +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +pl.title('Source and traget distributions') + + +# Cost matrices +pl.figure(2, figsize=(7, 3)) + +pl.subplot(1, 3, 1) +pl.imshow(M1, interpolation='nearest') +pl.title('Euclidean cost') + +pl.subplot(1, 3, 2) +pl.imshow(M2, interpolation='nearest') +pl.title('Squared Euclidean cost') + +pl.subplot(1, 3, 3) +pl.imshow(Mp, interpolation='nearest') +pl.title('Sqrt Euclidean cost') +pl.tight_layout() + +############################################################################## +# Dataset 1 : Plot OT Matrices +############################################################################## + + + +#%% EMD +G1 = ot.emd(a, b, M1) +G2 = ot.emd(a, b, M2) +Gp = ot.emd(a, b, Mp) + +# OT matrices +pl.figure(3, figsize=(7, 3)) + +pl.subplot(1, 3, 1) +ot.plot.plot2D_samples_mat(xs, xt, G1, c=[.5, .5, 1]) +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +# pl.legend(loc=0) +pl.title('OT Euclidean') + +pl.subplot(1, 3, 2) +ot.plot.plot2D_samples_mat(xs, xt, G2, c=[.5, .5, 1]) +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +# pl.legend(loc=0) +pl.title('OT squared Euclidean') + +pl.subplot(1, 3, 3) +ot.plot.plot2D_samples_mat(xs, xt, Gp, c=[.5, .5, 1]) +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +# pl.legend(loc=0) +pl.title('OT sqrt Euclidean') +pl.tight_layout() + +pl.show() + + +############################################################################## +# Dataset 2 : Partial circle +############################################################################## + +n = 50 # nb samples +xtot = np.zeros((n + 1, 2)) +xtot[:, 0] = np.cos( + (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi) +xtot[:, 1] = np.sin( + (np.arange(n + 1) + 1.0) * 0.9 / (n + 2) * 2 * np.pi) + +xs = xtot[:n, :] +xt = xtot[1:, :] + +a, b = ot.unif(n), ot.unif(n) # uniform distribution on samples + +# loss matrix +M1 = ot.dist(xs, xt, metric='euclidean') +M1 /= M1.max() + +# loss matrix +M2 = ot.dist(xs, xt, metric='sqeuclidean') +M2 /= M2.max() + +# loss matrix +Mp = np.sqrt(ot.dist(xs, xt, metric='euclidean')) +Mp /= Mp.max() + + +# Data +pl.figure(4, figsize=(7, 3)) +pl.clf() +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +pl.title('Source and traget distributions') + + +# Cost matrices +pl.figure(5, figsize=(7, 3)) + +pl.subplot(1, 3, 1) +pl.imshow(M1, interpolation='nearest') +pl.title('Euclidean cost') + +pl.subplot(1, 3, 2) +pl.imshow(M2, interpolation='nearest') +pl.title('Squared Euclidean cost') + +pl.subplot(1, 3, 3) +pl.imshow(Mp, interpolation='nearest') +pl.title('Sqrt Euclidean cost') +pl.tight_layout() + +############################################################################## +# Dataset 2 : Plot OT Matrices +############################################################################## + + + +#%% EMD +G1 = ot.emd(a, b, M1) +G2 = ot.emd(a, b, M2) +Gp = ot.emd(a, b, Mp) + +# OT matrices +pl.figure(6, figsize=(7, 3)) + +pl.subplot(1, 3, 1) +ot.plot.plot2D_samples_mat(xs, xt, G1, c=[.5, .5, 1]) +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +# pl.legend(loc=0) +pl.title('OT Euclidean') + +pl.subplot(1, 3, 2) +ot.plot.plot2D_samples_mat(xs, xt, G2, c=[.5, .5, 1]) +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +# pl.legend(loc=0) +pl.title('OT squared Euclidean') + +pl.subplot(1, 3, 3) +ot.plot.plot2D_samples_mat(xs, xt, Gp, c=[.5, .5, 1]) +pl.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +pl.plot(xt[:, 0], xt[:, 1], 'xr', label='Target samples') +pl.axis('equal') +# pl.legend(loc=0) +pl.title('OT sqrt Euclidean') +pl.tight_layout() pl.show() diff --git a/examples/plot_barycenter_1D.py b/examples/plot_barycenter_1D.py index f3be247..142b05e 100644 --- a/examples/plot_barycenter_1D.py +++ b/examples/plot_barycenter_1D.py @@ -4,7 +4,7 @@ 1D Wasserstein barycenter demo ============================== -This example illustrate the computation of regularized Wassersyein Barycenter +This example illustrates the computation of regularized Wassersyein Barycenter as proposed in [3]. @@ -25,6 +25,9 @@ import ot from mpl_toolkits.mplot3d import Axes3D # noqa from matplotlib.collections import PolyCollection +############################################################################## +# Generate data +############################################################################## #%% parameters @@ -45,6 +48,10 @@ n_distributions = A.shape[1] M = ot.utils.dist0(n) M /= M.max() +############################################################################## +# Plot data +############################################################################## + #%% plot the distributions pl.figure(1, figsize=(6.4, 3)) @@ -53,6 +60,10 @@ for i in range(n_distributions): pl.title('Distributions') pl.tight_layout() +############################################################################## +# Barycenter computation +############################################################################## + #%% barycenter computation alpha = 0.2 # 0<=alpha<=1 @@ -79,6 +90,10 @@ pl.legend() pl.title('Barycenters') pl.tight_layout() +############################################################################## +# Barycentric interpolation +############################################################################## + #%% barycenter interpolation n_alpha = 11 diff --git a/examples/plot_compute_emd.py b/examples/plot_compute_emd.py index 704da0e..b688f93 100644 --- a/examples/plot_compute_emd.py +++ b/examples/plot_compute_emd.py @@ -4,6 +4,10 @@ Plot multiple EMD ================= +Shows how to compute multiple EMD and Sinkhorn with two differnt +ground metrics and plot their values for diffeent distributions. + + """ # Author: Remi Flamary diff --git a/examples/plot_optim_OTreg.py b/examples/plot_optim_OTreg.py index 95bcdaf..b362662 100644 --- a/examples/plot_optim_OTreg.py +++ b/examples/plot_optim_OTreg.py @@ -4,8 +4,8 @@ Regularized OT with generic solver ================================== -This example illustrate the use of the generic solver for regularized OT with -user designed regularization term. It uses Conditional gradient as in [6] and +Illustrates the use of the generic solver for regularized OT with +user-designed regularization term. It uses Conditional gradient as in [6] and generalized Conditional Gradient as proposed in [5][7]. diff --git a/examples/plot_otda_mapping.py b/examples/plot_otda_mapping.py index e0da2d8..e78fef4 100644 --- a/examples/plot_otda_mapping.py +++ b/examples/plot_otda_mapping.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- """ -=============================================== -OT mapping estimation for domain adaptation [8] -=============================================== +=========================================== +OT mapping estimation for domain adaptation +=========================================== This example presents how to use MappingTransport to estimate at the same time both the coupling transport and approximate the transport map with either @@ -24,7 +24,7 @@ import ot ############################################################################## -# generate data +# Generate data ############################################################################## n_source_samples = 100 @@ -44,7 +44,7 @@ Xt[yt == 2] *= 3 Xt = Xt + 4 ############################################################################## -# plot data +# Plot data ############################################################################## pl.figure(1, (10, 5)) diff --git a/examples/plot_otda_mapping_colors_images.py b/examples/plot_otda_mapping_colors_images.py index a8b2ca8..162c24b 100644 --- a/examples/plot_otda_mapping_colors_images.py +++ b/examples/plot_otda_mapping_colors_images.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- """ -=============================================== -OT for color adaptation with mapping estimation -=============================================== +===================================================== +OT for image color adaptation with mapping estimation +===================================================== OT for domain adaptation with image color adaptation [6] with mapping estimation [8]. -- cgit v1.2.3 From 8ea3504c3bfe9c9440982f8ad0d172a240d54aff Mon Sep 17 00:00:00 2001 From: Rémi Flamary Date: Fri, 1 Sep 2017 17:55:32 +0200 Subject: good notebook format generated by sphinx gallery --- docs/nb_build | 3 +- .../source/auto_examples/auto_examples_jupyter.zip | Bin 70289 -> 67774 bytes docs/source/auto_examples/auto_examples_python.zip | Bin 46532 -> 44112 bytes .../images/sphx_glr_plot_OT_2D_samples_001.png | Bin 20707 -> 22153 bytes .../images/sphx_glr_plot_OT_2D_samples_002.png | Bin 21335 -> 21589 bytes .../images/sphx_glr_plot_OT_2D_samples_005.png | Bin 9613 -> 9645 bytes .../images/sphx_glr_plot_OT_2D_samples_006.png | Bin 83657 -> 91095 bytes .../images/sphx_glr_plot_OT_2D_samples_009.png | Bin 14178 -> 13987 bytes .../images/sphx_glr_plot_OT_2D_samples_010.png | Bin 98951 -> 109742 bytes .../auto_examples/images/sphx_glr_plot_WDA_001.png | Bin 55744 -> 54285 bytes .../auto_examples/images/sphx_glr_plot_WDA_003.png | Bin 86112 -> 86366 bytes .../images/sphx_glr_plot_otda_classes_001.png | Bin 49949 -> 51418 bytes .../images/sphx_glr_plot_otda_classes_003.png | Bin 189153 -> 199721 bytes .../images/sphx_glr_plot_otda_d2_001.png | Bin 131873 -> 135206 bytes .../images/sphx_glr_plot_otda_d2_003.png | Bin 240262 -> 241976 bytes .../images/sphx_glr_plot_otda_d2_006.png | Bin 104502 -> 108946 bytes .../images/sphx_glr_plot_otda_mapping_001.png | Bin 37940 -> 35881 bytes .../images/sphx_glr_plot_otda_mapping_003.png | Bin 76017 -> 73815 bytes .../thumb/sphx_glr_plot_OT_2D_samples_thumb.png | Bin 22370 -> 24711 bytes .../images/thumb/sphx_glr_plot_WDA_thumb.png | Bin 85660 -> 87479 bytes .../thumb/sphx_glr_plot_otda_classes_thumb.png | Bin 29948 -> 30678 bytes .../images/thumb/sphx_glr_plot_otda_d2_thumb.png | Bin 54746 -> 53014 bytes .../thumb/sphx_glr_plot_otda_mapping_thumb.png | Bin 19281 -> 18473 bytes docs/source/auto_examples/plot_OT_1D.ipynb | 6 +- docs/source/auto_examples/plot_OT_1D.py | 8 +- docs/source/auto_examples/plot_OT_1D.rst | 10 ++- docs/source/auto_examples/plot_OT_2D_samples.ipynb | 8 +- docs/source/auto_examples/plot_OT_2D_samples.py | 8 +- docs/source/auto_examples/plot_OT_2D_samples.rst | 10 +-- docs/source/auto_examples/plot_OT_L1_vs_L2.ipynb | 8 +- docs/source/auto_examples/plot_OT_L1_vs_L2.py | 8 +- docs/source/auto_examples/plot_OT_L1_vs_L2.rst | 10 +-- docs/source/auto_examples/plot_WDA.ipynb | 10 +-- docs/source/auto_examples/plot_WDA.py | 10 +-- docs/source/auto_examples/plot_WDA.rst | 82 ++++++--------------- docs/source/auto_examples/plot_barycenter_1D.ipynb | 8 +- docs/source/auto_examples/plot_barycenter_1D.py | 8 +- docs/source/auto_examples/plot_barycenter_1D.rst | 10 +-- docs/source/auto_examples/plot_compute_emd.ipynb | 8 +- docs/source/auto_examples/plot_compute_emd.py | 8 +- docs/source/auto_examples/plot_compute_emd.rst | 10 +-- docs/source/auto_examples/plot_optim_OTreg.ipynb | 10 +-- docs/source/auto_examples/plot_optim_OTreg.py | 10 +-- docs/source/auto_examples/plot_optim_OTreg.rst | 12 +-- docs/source/auto_examples/plot_otda_classes.ipynb | 8 +- docs/source/auto_examples/plot_otda_classes.py | 10 +-- docs/source/auto_examples/plot_otda_classes.rst | 54 +++++++------- .../auto_examples/plot_otda_color_images.ipynb | 10 +-- .../source/auto_examples/plot_otda_color_images.py | 10 +-- .../auto_examples/plot_otda_color_images.rst | 12 +-- docs/source/auto_examples/plot_otda_d2.ipynb | 12 +-- docs/source/auto_examples/plot_otda_d2.py | 17 ++--- docs/source/auto_examples/plot_otda_d2.rst | 19 +++-- docs/source/auto_examples/plot_otda_mapping.ipynb | 8 +- docs/source/auto_examples/plot_otda_mapping.py | 8 +- docs/source/auto_examples/plot_otda_mapping.rst | 44 ++++++----- .../plot_otda_mapping_colors_images.ipynb | 10 +-- .../plot_otda_mapping_colors_images.py | 10 +-- .../plot_otda_mapping_colors_images.rst | 12 +-- docs/source/conf.py | 2 +- 60 files changed, 235 insertions(+), 276 deletions(-) (limited to 'docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png') diff --git a/docs/nb_build b/docs/nb_build index 979a913..7f74c70 100755 --- a/docs/nb_build +++ b/docs/nb_build @@ -11,5 +11,4 @@ make html sed -i "s/'sphinx\_gallery/#'sphinx\_gallery/" source/conf.py sed -i "s/#sys.modules.update/sys.modules.update/" source/conf.py - - +#rsync --out-format="%n" --update source/auto_examples/*.ipynb ../notebooks2 diff --git a/docs/source/auto_examples/auto_examples_jupyter.zip b/docs/source/auto_examples/auto_examples_jupyter.zip index f7698ad..fc1d4de 100644 Binary files a/docs/source/auto_examples/auto_examples_jupyter.zip and b/docs/source/auto_examples/auto_examples_jupyter.zip differ diff --git a/docs/source/auto_examples/auto_examples_python.zip b/docs/source/auto_examples/auto_examples_python.zip index 6a8e449..92adf10 100644 Binary files a/docs/source/auto_examples/auto_examples_python.zip and b/docs/source/auto_examples/auto_examples_python.zip differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_001.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_001.png index 172d736..ba50e23 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_002.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_002.png index 3043a72..19978ff 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_002.png and b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_002.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_005.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_005.png index 5565d75..aed13b2 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_005.png and b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_005.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_006.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_006.png index 06d1020..8ea40f1 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_006.png and b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_006.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_009.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_009.png index 8c16aea..404e9d8 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_009.png and b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_009.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_010.png b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_010.png index ccfe1e0..56b79cf 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_010.png and b/docs/source/auto_examples/images/sphx_glr_plot_OT_2D_samples_010.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_WDA_001.png b/docs/source/auto_examples/images/sphx_glr_plot_WDA_001.png index 9048051..f724332 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_WDA_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_WDA_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_WDA_003.png b/docs/source/auto_examples/images/sphx_glr_plot_WDA_003.png index fcf13c6..b231020 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_WDA_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_WDA_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png index a28f245..bedc950 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_003.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_003.png index 4d0b12d..8e3ccad 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_001.png index 9e78aed..3d6a740 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_003.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_003.png index d37359b..aa16585 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_006.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_006.png index c71284a..5dc3ba7 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_006.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_006.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_001.png index d2ee139..4239465 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_003.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_003.png index fa1ab81..620105e 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_003.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_2D_samples_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_2D_samples_thumb.png index 1f42900..dbb5cfd 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_2D_samples_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_OT_2D_samples_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_WDA_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_WDA_thumb.png index 8db78a1..f55490c 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_WDA_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_WDA_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png index a2571a5..a72fe37 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png index 6c8f37f..cddf768 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png index a042411..959cc44 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png differ diff --git a/docs/source/auto_examples/plot_OT_1D.ipynb b/docs/source/auto_examples/plot_OT_1D.ipynb index c8925ac..26748c2 100644 --- a/docs/source/auto_examples/plot_OT_1D.ipynb +++ b/docs/source/auto_examples/plot_OT_1D.ipynb @@ -51,7 +51,7 @@ }, { "source": [ - "Plot distributions and loss matrix\n##################################\n\n" + "Plot distributions and loss matrix\n----------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -69,7 +69,7 @@ }, { "source": [ - "Solve EMD\n#############################################################################\n\n" + "Solve EMD\n---------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -87,7 +87,7 @@ }, { "source": [ - "Solve Sinkhorn\n#############################################################################\n\n" + "Solve Sinkhorn\n--------------\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_OT_1D.py b/docs/source/auto_examples/plot_OT_1D.py index 36f823f..719058f 100644 --- a/docs/source/auto_examples/plot_OT_1D.py +++ b/docs/source/auto_examples/plot_OT_1D.py @@ -41,7 +41,7 @@ M /= M.max() ############################################################################## # Plot distributions and loss matrix -################################### +# ---------------------------------- #%% plot the distributions @@ -57,7 +57,8 @@ ot.plot.plot1D_mat(a, b, M, 'Cost matrix M') ############################################################################## # Solve EMD -############################################################################## +# --------- + #%% EMD @@ -68,7 +69,8 @@ ot.plot.plot1D_mat(a, b, G0, 'OT matrix G0') ############################################################################## # Solve Sinkhorn -############################################################################## +# -------------- + #%% Sinkhorn diff --git a/docs/source/auto_examples/plot_OT_1D.rst b/docs/source/auto_examples/plot_OT_1D.rst index 32a88e7..b91916e 100644 --- a/docs/source/auto_examples/plot_OT_1D.rst +++ b/docs/source/auto_examples/plot_OT_1D.rst @@ -63,7 +63,7 @@ Generate data Plot distributions and loss matrix -################################## +---------------------------------- @@ -102,13 +102,14 @@ Plot distributions and loss matrix Solve EMD -############################################################################# +--------- .. code-block:: python + #%% EMD G0 = ot.emd(a, b, M) @@ -126,13 +127,14 @@ Solve EMD Solve Sinkhorn -############################################################################# +-------------- .. code-block:: python + #%% Sinkhorn lambd = 1e-3 @@ -169,7 +171,7 @@ Solve Sinkhorn 110|1.527180e-10| -**Total running time of the script:** ( 0 minutes 0.754 seconds) +**Total running time of the script:** ( 0 minutes 0.748 seconds) diff --git a/docs/source/auto_examples/plot_OT_2D_samples.ipynb b/docs/source/auto_examples/plot_OT_2D_samples.ipynb index 0ed7367..41a37f3 100644 --- a/docs/source/auto_examples/plot_OT_2D_samples.ipynb +++ b/docs/source/auto_examples/plot_OT_2D_samples.ipynb @@ -33,7 +33,7 @@ }, { "source": [ - "Generate data\n#############################################################################\n\n" + "Generate data\n-------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -51,7 +51,7 @@ }, { "source": [ - "Plot data\n#############################################################################\n\n" + "Plot data\n---------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -69,7 +69,7 @@ }, { "source": [ - "Compute EMD\n#############################################################################\n\n" + "Compute EMD\n-----------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -87,7 +87,7 @@ }, { "source": [ - "Compute Sinkhorn\n#############################################################################\n\n" + "Compute Sinkhorn\n----------------\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_OT_2D_samples.py b/docs/source/auto_examples/plot_OT_2D_samples.py index f57d631..9818ec5 100644 --- a/docs/source/auto_examples/plot_OT_2D_samples.py +++ b/docs/source/auto_examples/plot_OT_2D_samples.py @@ -19,7 +19,7 @@ import ot ############################################################################## # Generate data -############################################################################## +# ------------- #%% parameters and data generation @@ -42,7 +42,7 @@ M /= M.max() ############################################################################## # Plot data -############################################################################## +# --------- #%% plot samples @@ -58,7 +58,7 @@ pl.title('Cost matrix M') ############################################################################## # Compute EMD -############################################################################## +# ----------- #%% EMD @@ -78,7 +78,7 @@ pl.title('OT matrix with samples') ############################################################################## # Compute Sinkhorn -############################################################################## +# ---------------- #%% sinkhorn diff --git a/docs/source/auto_examples/plot_OT_2D_samples.rst b/docs/source/auto_examples/plot_OT_2D_samples.rst index f95ffaf..0ad9cf0 100644 --- a/docs/source/auto_examples/plot_OT_2D_samples.rst +++ b/docs/source/auto_examples/plot_OT_2D_samples.rst @@ -31,7 +31,7 @@ sum of diracs. The OT matrix is plotted with the samples. Generate data -############################################################################# +------------- @@ -64,7 +64,7 @@ Generate data Plot data -############################################################################# +--------- @@ -103,7 +103,7 @@ Plot data Compute EMD -############################################################################# +----------- @@ -146,7 +146,7 @@ Compute EMD Compute Sinkhorn -############################################################################# +---------------- @@ -191,7 +191,7 @@ Compute Sinkhorn -**Total running time of the script:** ( 0 minutes 1.990 seconds) +**Total running time of the script:** ( 0 minutes 1.743 seconds) diff --git a/docs/source/auto_examples/plot_OT_L1_vs_L2.ipynb b/docs/source/auto_examples/plot_OT_L1_vs_L2.ipynb index e738db7..2b9a364 100644 --- a/docs/source/auto_examples/plot_OT_L1_vs_L2.ipynb +++ b/docs/source/auto_examples/plot_OT_L1_vs_L2.ipynb @@ -33,7 +33,7 @@ }, { "source": [ - "Dataset 1 : uniform sampling\n#############################################################################\n\n" + "Dataset 1 : uniform sampling\n----------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -51,7 +51,7 @@ }, { "source": [ - "Dataset 1 : Plot OT Matrices\n#############################################################################\n\n" + "Dataset 1 : Plot OT Matrices\n----------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -69,7 +69,7 @@ }, { "source": [ - "Dataset 2 : Partial circle\n#############################################################################\n\n" + "Dataset 2 : Partial circle\n--------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -87,7 +87,7 @@ }, { "source": [ - "Dataset 2 : Plot OT Matrices\n#############################################################################\n\n" + "Dataset 2 : Plot OT Matrices\n-----------------------------\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_OT_L1_vs_L2.py b/docs/source/auto_examples/plot_OT_L1_vs_L2.py index 49d37e1..090e809 100644 --- a/docs/source/auto_examples/plot_OT_L1_vs_L2.py +++ b/docs/source/auto_examples/plot_OT_L1_vs_L2.py @@ -22,7 +22,7 @@ import ot ############################################################################## # Dataset 1 : uniform sampling -############################################################################## +# ---------------------------- n = 20 # nb samples xs = np.zeros((n, 2)) @@ -73,7 +73,7 @@ pl.tight_layout() ############################################################################## # Dataset 1 : Plot OT Matrices -############################################################################## +# ---------------------------- #%% EMD @@ -114,7 +114,7 @@ pl.show() ############################################################################## # Dataset 2 : Partial circle -############################################################################## +# -------------------------- n = 50 # nb samples xtot = np.zeros((n + 1, 2)) @@ -168,7 +168,7 @@ pl.tight_layout() ############################################################################## # Dataset 2 : Plot OT Matrices -############################################################################## +# ----------------------------- #%% EMD diff --git a/docs/source/auto_examples/plot_OT_L1_vs_L2.rst b/docs/source/auto_examples/plot_OT_L1_vs_L2.rst index 8b5b133..f97b373 100644 --- a/docs/source/auto_examples/plot_OT_L1_vs_L2.rst +++ b/docs/source/auto_examples/plot_OT_L1_vs_L2.rst @@ -34,7 +34,7 @@ https://arxiv.org/pdf/1706.07650.pdf Dataset 1 : uniform sampling -############################################################################# +---------------------------- @@ -108,7 +108,7 @@ Dataset 1 : uniform sampling Dataset 1 : Plot OT Matrices -############################################################################# +---------------------------- @@ -162,7 +162,7 @@ Dataset 1 : Plot OT Matrices Dataset 2 : Partial circle -############################################################################# +-------------------------- @@ -239,7 +239,7 @@ Dataset 2 : Partial circle Dataset 2 : Plot OT Matrices -############################################################################# +----------------------------- @@ -290,7 +290,7 @@ Dataset 2 : Plot OT Matrices -**Total running time of the script:** ( 0 minutes 1.218 seconds) +**Total running time of the script:** ( 0 minutes 1.134 seconds) diff --git a/docs/source/auto_examples/plot_WDA.ipynb b/docs/source/auto_examples/plot_WDA.ipynb index 47a6eca..1661c53 100644 --- a/docs/source/auto_examples/plot_WDA.ipynb +++ b/docs/source/auto_examples/plot_WDA.ipynb @@ -33,7 +33,7 @@ }, { "source": [ - "Generate data\n#############################################################################\n\n" + "Generate data\n-------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -51,7 +51,7 @@ }, { "source": [ - "Plot data\n#############################################################################\n\n" + "Plot data\n---------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -69,7 +69,7 @@ }, { "source": [ - "Compute Fisher Discriminant Analysis\n#############################################################################\n\n" + "Compute Fisher Discriminant Analysis\n------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -87,7 +87,7 @@ }, { "source": [ - "Compute Wasserstein Discriminant Analysis\n#############################################################################\n\n" + "Compute Wasserstein Discriminant Analysis\n-----------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -105,7 +105,7 @@ }, { "source": [ - "Plot 2D projections\n#############################################################################\n\n" + "Plot 2D projections\n-------------------\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_WDA.py b/docs/source/auto_examples/plot_WDA.py index 5928621..93cc237 100644 --- a/docs/source/auto_examples/plot_WDA.py +++ b/docs/source/auto_examples/plot_WDA.py @@ -24,7 +24,7 @@ from ot.dr import wda, fda ############################################################################## # Generate data -############################################################################## +# ------------- #%% parameters @@ -51,7 +51,7 @@ xt = np.hstack((xt, np.random.randn(n, nbnoise))) ############################################################################## # Plot data -############################################################################## +# --------- #%% plot samples pl.figure(1, figsize=(6.4, 3.5)) @@ -69,7 +69,7 @@ pl.tight_layout() ############################################################################## # Compute Fisher Discriminant Analysis -############################################################################## +# ------------------------------------ #%% Compute FDA p = 2 @@ -78,7 +78,7 @@ Pfda, projfda = fda(xs, ys, p) ############################################################################## # Compute Wasserstein Discriminant Analysis -############################################################################## +# ----------------------------------------- #%% Compute WDA p = 2 @@ -91,7 +91,7 @@ Pwda, projwda = wda(xs, ys, p, reg, k, maxiter=maxiter) ############################################################################## # Plot 2D projections -############################################################################## +# ------------------- #%% plot samples diff --git a/docs/source/auto_examples/plot_WDA.rst b/docs/source/auto_examples/plot_WDA.rst index a0c3389..64ddb47 100644 --- a/docs/source/auto_examples/plot_WDA.rst +++ b/docs/source/auto_examples/plot_WDA.rst @@ -36,7 +36,7 @@ Wasserstein Discriminant Analysis. Generate data -############################################################################# +------------- @@ -73,7 +73,7 @@ Generate data Plot data -############################################################################# +--------- @@ -104,7 +104,7 @@ Plot data Compute Fisher Discriminant Analysis -############################################################################# +------------------------------------ @@ -123,7 +123,7 @@ Compute Fisher Discriminant Analysis Compute Wasserstein Discriminant Analysis -############################################################################# +----------------------------------------- @@ -150,65 +150,25 @@ Compute Wasserstein Discriminant Analysis Compiling cost function... Computing gradient of cost function... iter cost val grad. norm - 1 +8.6305817354868675e-01 4.10110152e-01 - 2 +4.6939060757969131e-01 2.98553763e-01 - 3 +4.2106314200107775e-01 1.48552668e-01 - 4 +4.1376389458568069e-01 1.12319011e-01 - 5 +4.0984854988792835e-01 1.01126129e-01 - 6 +4.0415292614140025e-01 3.90875165e-02 - 7 +4.0297967887432584e-01 2.73716014e-02 - 8 +4.0252319029045258e-01 3.76498956e-02 - 9 +4.0158635935184972e-01 1.31986577e-02 - 10 +4.0118906894272482e-01 3.40307273e-02 - 11 +4.0052579694802176e-01 7.79567347e-03 - 12 +4.0049330810825384e-01 9.77921941e-03 - 13 +4.0042500151972926e-01 4.63602913e-03 - 14 +4.0031705300038767e-01 1.69742018e-02 - 15 +4.0013705338124350e-01 7.40310798e-03 - 16 +4.0006224569843946e-01 1.08829949e-02 - 17 +3.9998280287782945e-01 1.25733450e-02 - 18 +3.9986405111843215e-01 1.05626807e-02 - 19 +3.9974905002724365e-01 9.93566406e-03 - 20 +3.9971323753531823e-01 2.21199533e-02 - 21 +3.9958582328238779e-01 1.73335808e-02 - 22 +3.9937139582811110e-01 1.09182412e-02 - 23 +3.9923748818499571e-01 1.77304913e-02 - 24 +3.9900530515251881e-01 1.15381586e-02 - 25 +3.9883316307006128e-01 1.80225446e-02 - 26 +3.9860317631835845e-01 1.65011032e-02 - 27 +3.9852130309759393e-01 2.81245689e-02 - 28 +3.9824281033694675e-01 2.01114810e-02 - 29 +3.9799657608114836e-01 2.66040929e-02 - 30 +3.9746233677210713e-01 1.45779937e-02 - 31 +3.9671794378467928e-01 4.27487207e-02 - 32 +3.9573357685391913e-01 2.20071520e-02 - 33 +3.9536725156297214e-01 2.00817458e-02 - 34 +3.9515994339814914e-01 3.81472315e-02 - 35 +3.9448966390371887e-01 2.52129049e-02 - 36 +3.9351423238681266e-01 5.60677866e-02 - 37 +3.9082703288308568e-01 4.26859586e-02 - 38 +3.7139409489868136e-01 1.26067835e-01 - 39 +2.8085932518253526e-01 1.70133509e-01 - 40 +2.7330384726281814e-01 1.95523507e-01 - 41 +2.4806985554269162e-01 1.31192016e-01 - 42 +2.3748356968454920e-01 8.71616829e-02 - 43 +2.3501927152342389e-01 7.02789537e-02 - 44 +2.3183578112546338e-01 2.62025296e-02 - 45 +2.3154208568082749e-01 1.67845346e-02 - 46 +2.3139316710346300e-01 8.27285074e-03 - 47 +2.3136034106523354e-01 4.64818210e-03 - 48 +2.3134548827742521e-01 4.53144806e-04 - 49 +2.3134540503271503e-01 2.91010390e-04 - 50 +2.3134535764073319e-01 1.25662481e-04 - 51 +2.3134534692621381e-01 1.24751216e-05 - 52 +2.3134534685831357e-01 7.44008265e-06 - 53 +2.3134534684658337e-01 6.16933546e-06 - 54 +2.3134534682129679e-01 5.12152219e-07 - Terminated - min grad norm reached after 54 iterations, 24.53 seconds. + 1 +5.4993226050368416e-01 5.18285173e-01 + 2 +3.4883000507542844e-01 1.96795818e-01 + 3 +2.9841234004693890e-01 2.33029475e-01 + 4 +2.3976476757548179e-01 1.38593951e-01 + 5 +2.3614468346177828e-01 1.19615394e-01 + 6 +2.2586536502789240e-01 4.82430685e-02 + 7 +2.2451030967794622e-01 2.56564039e-02 + 8 +2.2421446331083625e-01 1.47932578e-02 + 9 +2.2407441444450052e-01 1.12040327e-03 + 10 +2.2407365923337522e-01 3.78899763e-04 + 11 +2.2407356874011675e-01 1.79740810e-05 + 12 +2.2407356862959993e-01 1.25643005e-05 + 13 +2.2407356853043561e-01 1.40415001e-06 + 14 +2.2407356852925220e-01 3.41183585e-07 + Terminated - min grad norm reached after 14 iterations, 6.78 seconds. Plot 2D projections -############################################################################# +------------------- @@ -256,7 +216,7 @@ Plot 2D projections -**Total running time of the script:** ( 0 minutes 25.326 seconds) +**Total running time of the script:** ( 0 minutes 7.637 seconds) diff --git a/docs/source/auto_examples/plot_barycenter_1D.ipynb b/docs/source/auto_examples/plot_barycenter_1D.ipynb index 32cb2ec..a19e0fd 100644 --- a/docs/source/auto_examples/plot_barycenter_1D.ipynb +++ b/docs/source/auto_examples/plot_barycenter_1D.ipynb @@ -33,7 +33,7 @@ }, { "source": [ - "Generate data\n#############################################################################\n\n" + "Generate data\n-------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -51,7 +51,7 @@ }, { "source": [ - "Plot data\n#############################################################################\n\n" + "Plot data\n---------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -69,7 +69,7 @@ }, { "source": [ - "Barycenter computation\n#############################################################################\n\n" + "Barycenter computation\n----------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -87,7 +87,7 @@ }, { "source": [ - "Barycentric interpolation\n#############################################################################\n\n" + "Barycentric interpolation\n-------------------------\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_barycenter_1D.py b/docs/source/auto_examples/plot_barycenter_1D.py index eef8536..620936b 100644 --- a/docs/source/auto_examples/plot_barycenter_1D.py +++ b/docs/source/auto_examples/plot_barycenter_1D.py @@ -27,7 +27,7 @@ from matplotlib.collections import PolyCollection ############################################################################## # Generate data -############################################################################## +# ------------- #%% parameters @@ -50,7 +50,7 @@ M /= M.max() ############################################################################## # Plot data -############################################################################## +# --------- #%% plot the distributions @@ -62,7 +62,7 @@ pl.tight_layout() ############################################################################## # Barycenter computation -############################################################################## +# ---------------------- #%% barycenter computation @@ -92,7 +92,7 @@ pl.tight_layout() ############################################################################## # Barycentric interpolation -############################################################################## +# ------------------------- #%% barycenter interpolation diff --git a/docs/source/auto_examples/plot_barycenter_1D.rst b/docs/source/auto_examples/plot_barycenter_1D.rst index b1794cd..413fae3 100644 --- a/docs/source/auto_examples/plot_barycenter_1D.rst +++ b/docs/source/auto_examples/plot_barycenter_1D.rst @@ -39,7 +39,7 @@ SIAM Journal on Scientific Computing, 37(2), A1111-A1138. Generate data -############################################################################# +------------- @@ -72,7 +72,7 @@ Generate data Plot data -############################################################################# +--------- @@ -97,7 +97,7 @@ Plot data Barycenter computation -############################################################################# +---------------------- @@ -140,7 +140,7 @@ Barycenter computation Barycentric interpolation -############################################################################# +------------------------- @@ -230,7 +230,7 @@ Barycentric interpolation -**Total running time of the script:** ( 0 minutes 0.416 seconds) +**Total running time of the script:** ( 0 minutes 0.431 seconds) diff --git a/docs/source/auto_examples/plot_compute_emd.ipynb b/docs/source/auto_examples/plot_compute_emd.ipynb index a882bd1..b9b8bc5 100644 --- a/docs/source/auto_examples/plot_compute_emd.ipynb +++ b/docs/source/auto_examples/plot_compute_emd.ipynb @@ -33,7 +33,7 @@ }, { "source": [ - "Generate data\n#############################################################################\n\n" + "Generate data\n-------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -51,7 +51,7 @@ }, { "source": [ - "Plot data\n#############################################################################\n\n" + "Plot data\n---------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -69,7 +69,7 @@ }, { "source": [ - "Compute EMD for the different losses\n#############################################################################\n\n" + "Compute EMD for the different losses\n------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -87,7 +87,7 @@ }, { "source": [ - "Compute Sinkhorn for the different losses\n#############################################################################\n\n" + "Compute Sinkhorn for the different losses\n-----------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_compute_emd.py b/docs/source/auto_examples/plot_compute_emd.py index a84b249..73b42c3 100644 --- a/docs/source/auto_examples/plot_compute_emd.py +++ b/docs/source/auto_examples/plot_compute_emd.py @@ -22,7 +22,7 @@ from ot.datasets import get_1D_gauss as gauss ############################################################################## # Generate data -############################################################################## +# ------------- #%% parameters @@ -51,7 +51,7 @@ M2 /= M2.max() ############################################################################## # Plot data -############################################################################## +# --------- #%% plot the distributions @@ -67,7 +67,7 @@ pl.tight_layout() ############################################################################## # Compute EMD for the different losses -############################################################################## +# ------------------------------------ #%% Compute and plot distributions and loss matrix @@ -83,7 +83,7 @@ pl.legend() ############################################################################## # Compute Sinkhorn for the different losses -############################################################################## +# ----------------------------------------- #%% reg = 1e-2 diff --git a/docs/source/auto_examples/plot_compute_emd.rst b/docs/source/auto_examples/plot_compute_emd.rst index 58220a4..ce79e20 100644 --- a/docs/source/auto_examples/plot_compute_emd.rst +++ b/docs/source/auto_examples/plot_compute_emd.rst @@ -34,7 +34,7 @@ ground metrics and plot their values for diffeent distributions. Generate data -############################################################################# +------------- @@ -73,7 +73,7 @@ Generate data Plot data -############################################################################# +--------- @@ -102,7 +102,7 @@ Plot data Compute EMD for the different losses -############################################################################# +------------------------------------ @@ -131,7 +131,7 @@ Compute EMD for the different losses Compute Sinkhorn for the different losses -############################################################################# +----------------------------------------- @@ -162,7 +162,7 @@ Compute Sinkhorn for the different losses -**Total running time of the script:** ( 0 minutes 0.471 seconds) +**Total running time of the script:** ( 0 minutes 0.441 seconds) diff --git a/docs/source/auto_examples/plot_optim_OTreg.ipynb b/docs/source/auto_examples/plot_optim_OTreg.ipynb index f9fec33..333331b 100644 --- a/docs/source/auto_examples/plot_optim_OTreg.ipynb +++ b/docs/source/auto_examples/plot_optim_OTreg.ipynb @@ -33,7 +33,7 @@ }, { "source": [ - "Generate data\n#############################################################################\n\n" + "Generate data\n-------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -51,7 +51,7 @@ }, { "source": [ - "Solve EMD\n#############################################################################\n\n" + "Solve EMD\n---------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -69,7 +69,7 @@ }, { "source": [ - "Solve EMD with Frobenius norm regularization\n#############################################################################\n\n" + "Solve EMD with Frobenius norm regularization\n--------------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -87,7 +87,7 @@ }, { "source": [ - "Solve EMD with entropic regularization\n#############################################################################\n\n" + "Solve EMD with entropic regularization\n--------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -105,7 +105,7 @@ }, { "source": [ - "Solve EMD with Frobenius norm + entropic regularization\n#############################################################################\n\n" + "Solve EMD with Frobenius norm + entropic regularization\n-------------------------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_optim_OTreg.py b/docs/source/auto_examples/plot_optim_OTreg.py index d753414..e1a737e 100644 --- a/docs/source/auto_examples/plot_optim_OTreg.py +++ b/docs/source/auto_examples/plot_optim_OTreg.py @@ -32,7 +32,7 @@ import ot ############################################################################## # Generate data -############################################################################## +# ------------- #%% parameters @@ -51,7 +51,7 @@ M /= M.max() ############################################################################## # Solve EMD -############################################################################## +# --------- #%% EMD @@ -62,7 +62,7 @@ ot.plot.plot1D_mat(a, b, G0, 'OT matrix G0') ############################################################################## # Solve EMD with Frobenius norm regularization -############################################################################## +# -------------------------------------------- #%% Example with Frobenius norm regularization @@ -84,7 +84,7 @@ ot.plot.plot1D_mat(a, b, Gl2, 'OT matrix Frob. reg') ############################################################################## # Solve EMD with entropic regularization -############################################################################## +# -------------------------------------- #%% Example with entropic regularization @@ -106,7 +106,7 @@ ot.plot.plot1D_mat(a, b, Ge, 'OT matrix Entrop. reg') ############################################################################## # Solve EMD with Frobenius norm + entropic regularization -############################################################################## +# ------------------------------------------------------- #%% Example with Frobenius norm + entropic regularization with gcg diff --git a/docs/source/auto_examples/plot_optim_OTreg.rst b/docs/source/auto_examples/plot_optim_OTreg.rst index c3ec03b..f628024 100644 --- a/docs/source/auto_examples/plot_optim_OTreg.rst +++ b/docs/source/auto_examples/plot_optim_OTreg.rst @@ -44,7 +44,7 @@ arXiv preprint arXiv:1510.06567. Generate data -############################################################################# +------------- @@ -73,7 +73,7 @@ Generate data Solve EMD -############################################################################# +--------- @@ -97,7 +97,7 @@ Solve EMD Solve EMD with Frobenius norm regularization -############################################################################# +-------------------------------------------- @@ -359,7 +359,7 @@ Solve EMD with Frobenius norm regularization Solve EMD with entropic regularization -############################################################################# +-------------------------------------- @@ -621,7 +621,7 @@ Solve EMD with entropic regularization Solve EMD with Frobenius norm + entropic regularization -############################################################################# +------------------------------------------------------- @@ -667,7 +667,7 @@ Solve EMD with Frobenius norm + entropic regularization 4|1.609284e-01|-1.111407e-12 -**Total running time of the script:** ( 0 minutes 1.913 seconds) +**Total running time of the script:** ( 0 minutes 1.809 seconds) diff --git a/docs/source/auto_examples/plot_otda_classes.ipynb b/docs/source/auto_examples/plot_otda_classes.ipynb index 16634b1..6754fa5 100644 --- a/docs/source/auto_examples/plot_otda_classes.ipynb +++ b/docs/source/auto_examples/plot_otda_classes.ipynb @@ -33,7 +33,7 @@ }, { "source": [ - "generate data\n#############################################################################\n\n" + "Generate data\n-------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -51,7 +51,7 @@ }, { "source": [ - "Instantiate the different transport algorithms and fit them\n#############################################################################\n\n" + "Instantiate the different transport algorithms and fit them\n-----------------------------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -69,7 +69,7 @@ }, { "source": [ - "Fig 1 : plots source and target samples\n#############################################################################\n\n" + "Fig 1 : plots source and target samples\n---------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -87,7 +87,7 @@ }, { "source": [ - "Fig 2 : plot optimal couplings and transported samples\n#############################################################################\n\n" + "Fig 2 : plot optimal couplings and transported samples\n------------------------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_otda_classes.py b/docs/source/auto_examples/plot_otda_classes.py index ec57a37..b14c11a 100644 --- a/docs/source/auto_examples/plot_otda_classes.py +++ b/docs/source/auto_examples/plot_otda_classes.py @@ -19,8 +19,8 @@ import ot ############################################################################## -# generate data -############################################################################## +# Generate data +# ------------- n_source_samples = 150 n_target_samples = 150 @@ -31,7 +31,7 @@ Xt, yt = ot.datasets.get_data_classif('3gauss2', n_target_samples) ############################################################################## # Instantiate the different transport algorithms and fit them -############################################################################## +# ----------------------------------------------------------- # EMD Transport ot_emd = ot.da.EMDTransport() @@ -59,7 +59,7 @@ transp_Xs_l1l2 = ot_l1l2.transform(Xs=Xs) ############################################################################## # Fig 1 : plots source and target samples -############################################################################## +# --------------------------------------- pl.figure(1, figsize=(10, 5)) pl.subplot(1, 2, 1) @@ -80,7 +80,7 @@ pl.tight_layout() ############################################################################## # Fig 2 : plot optimal couplings and transported samples -############################################################################## +# ------------------------------------------------------ param_img = {'interpolation': 'nearest', 'cmap': 'spectral'} diff --git a/docs/source/auto_examples/plot_otda_classes.rst b/docs/source/auto_examples/plot_otda_classes.rst index d1a13b1..f19a99f 100644 --- a/docs/source/auto_examples/plot_otda_classes.rst +++ b/docs/source/auto_examples/plot_otda_classes.rst @@ -31,8 +31,8 @@ approaches currently supported in POT. -generate data -############################################################################# +Generate data +------------- @@ -53,7 +53,7 @@ generate data Instantiate the different transport algorithms and fit them -############################################################################# +----------------------------------------------------------- @@ -94,33 +94,33 @@ Instantiate the different transport algorithms and fit them It. |Loss |Delta loss -------------------------------- - 0|9.984935e+00|0.000000e+00 - 1|2.126803e+00|-3.694808e+00 - 2|1.867272e+00|-1.389895e-01 - 3|1.803858e+00|-3.515488e-02 - 4|1.783036e+00|-1.167761e-02 - 5|1.774823e+00|-4.627422e-03 - 6|1.771947e+00|-1.623526e-03 - 7|1.767564e+00|-2.479535e-03 - 8|1.763484e+00|-2.313667e-03 - 9|1.761138e+00|-1.331780e-03 - 10|1.758879e+00|-1.284576e-03 - 11|1.758034e+00|-4.806014e-04 - 12|1.757595e+00|-2.497155e-04 - 13|1.756749e+00|-4.818562e-04 - 14|1.755316e+00|-8.161432e-04 - 15|1.754988e+00|-1.866236e-04 - 16|1.754964e+00|-1.382474e-05 - 17|1.754032e+00|-5.315971e-04 - 18|1.753595e+00|-2.492359e-04 - 19|1.752900e+00|-3.961403e-04 + 0|9.552437e+00|0.000000e+00 + 1|1.921833e+00|-3.970483e+00 + 2|1.671022e+00|-1.500942e-01 + 3|1.615147e+00|-3.459458e-02 + 4|1.594289e+00|-1.308252e-02 + 5|1.587287e+00|-4.411254e-03 + 6|1.581665e+00|-3.554702e-03 + 7|1.577022e+00|-2.943809e-03 + 8|1.573870e+00|-2.002870e-03 + 9|1.571645e+00|-1.415696e-03 + 10|1.569342e+00|-1.467590e-03 + 11|1.567863e+00|-9.432233e-04 + 12|1.566558e+00|-8.329769e-04 + 13|1.565414e+00|-7.311320e-04 + 14|1.564425e+00|-6.319985e-04 + 15|1.563955e+00|-3.007604e-04 + 16|1.563658e+00|-1.894627e-04 + 17|1.562886e+00|-4.941143e-04 + 18|1.562578e+00|-1.974031e-04 + 19|1.562445e+00|-8.468825e-05 It. |Loss |Delta loss -------------------------------- - 20|1.752850e+00|-2.869262e-05 + 20|1.562007e+00|-2.805136e-04 Fig 1 : plots source and target samples -############################################################################# +--------------------------------------- @@ -154,7 +154,7 @@ Fig 1 : plots source and target samples Fig 2 : plot optimal couplings and transported samples -############################################################################# +------------------------------------------------------ @@ -236,7 +236,7 @@ Fig 2 : plot optimal couplings and transported samples -**Total running time of the script:** ( 0 minutes 1.576 seconds) +**Total running time of the script:** ( 0 minutes 1.596 seconds) diff --git a/docs/source/auto_examples/plot_otda_color_images.ipynb b/docs/source/auto_examples/plot_otda_color_images.ipynb index 797b27d..2daf406 100644 --- a/docs/source/auto_examples/plot_otda_color_images.ipynb +++ b/docs/source/auto_examples/plot_otda_color_images.ipynb @@ -33,7 +33,7 @@ }, { "source": [ - "Generate data\n#############################################################################\n\n" + "Generate data\n-------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -51,7 +51,7 @@ }, { "source": [ - "Plot original image\n#############################################################################\n\n" + "Plot original image\n-------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -69,7 +69,7 @@ }, { "source": [ - "Scatter plot of colors\n#############################################################################\n\n" + "Scatter plot of colors\n----------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -87,7 +87,7 @@ }, { "source": [ - "Instantiate the different transport algorithms and fit them\n#############################################################################\n\n" + "Instantiate the different transport algorithms and fit them\n-----------------------------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -105,7 +105,7 @@ }, { "source": [ - "Plot new images\n#############################################################################\n\n" + "Plot new images\n---------------\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_otda_color_images.py b/docs/source/auto_examples/plot_otda_color_images.py index f1df9d9..e77aec0 100644 --- a/docs/source/auto_examples/plot_otda_color_images.py +++ b/docs/source/auto_examples/plot_otda_color_images.py @@ -42,7 +42,7 @@ def minmax(I): ############################################################################## # Generate data -############################################################################## +# ------------- # Loading images I1 = ndimage.imread('../data/ocean_day.jpg').astype(np.float64) / 256 @@ -62,7 +62,7 @@ Xt = X2[idx2, :] ############################################################################## # Plot original image -############################################################################## +# ------------------- pl.figure(1, figsize=(6.4, 3)) @@ -79,7 +79,7 @@ pl.title('Image 2') ############################################################################## # Scatter plot of colors -############################################################################## +# ---------------------- pl.figure(2, figsize=(6.4, 3)) @@ -101,7 +101,7 @@ pl.tight_layout() ############################################################################## # Instantiate the different transport algorithms and fit them -############################################################################## +# ----------------------------------------------------------- # EMDTransport ot_emd = ot.da.EMDTransport() @@ -127,7 +127,7 @@ I2te = minmax(mat2im(transp_Xt_sinkhorn, I2.shape)) ############################################################################## # Plot new images -############################################################################## +# --------------- pl.figure(3, figsize=(8, 4)) diff --git a/docs/source/auto_examples/plot_otda_color_images.rst b/docs/source/auto_examples/plot_otda_color_images.rst index 88e93d2..4772bed 100644 --- a/docs/source/auto_examples/plot_otda_color_images.rst +++ b/docs/source/auto_examples/plot_otda_color_images.rst @@ -54,7 +54,7 @@ SIAM Journal on Imaging Sciences, 7(3), 1853-1882. Generate data -############################################################################# +------------- @@ -84,7 +84,7 @@ Generate data Plot original image -############################################################################# +------------------- @@ -114,7 +114,7 @@ Plot original image Scatter plot of colors -############################################################################# +---------------------- @@ -149,7 +149,7 @@ Scatter plot of colors Instantiate the different transport algorithms and fit them -############################################################################# +----------------------------------------------------------- @@ -185,7 +185,7 @@ Instantiate the different transport algorithms and fit them Plot new images -############################################################################# +--------------- @@ -235,7 +235,7 @@ Plot new images -**Total running time of the script:** ( 2 minutes 28.053 seconds) +**Total running time of the script:** ( 2 minutes 24.561 seconds) diff --git a/docs/source/auto_examples/plot_otda_d2.ipynb b/docs/source/auto_examples/plot_otda_d2.ipynb index 2331f8c..7bfcc9a 100644 --- a/docs/source/auto_examples/plot_otda_d2.ipynb +++ b/docs/source/auto_examples/plot_otda_d2.ipynb @@ -15,7 +15,7 @@ }, { "source": [ - "\n# OT for empirical distributions\n\n\nThis example introduces a domain adaptation in a 2D setting. It explicits\nthe problem of domain adaptation and introduces some optimal transport\napproaches to solve it.\n\nQuantities such as optimal couplings, greater coupling coefficients and\ntransported samples are represented in order to give a visual understanding\nof what the transport methods are doing.\n\n" + "\n# OT for domain adaptation on empirical distributions\n\n\nThis example introduces a domain adaptation in a 2D setting. It explicits\nthe problem of domain adaptation and introduces some optimal transport\napproaches to solve it.\n\nQuantities such as optimal couplings, greater coupling coefficients and\ntransported samples are represented in order to give a visual understanding\nof what the transport methods are doing.\n\n" ], "cell_type": "markdown", "metadata": {} @@ -33,7 +33,7 @@ }, { "source": [ - "generate data\n#############################################################################\n\n" + "generate data\n-------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -51,7 +51,7 @@ }, { "source": [ - "Instantiate the different transport algorithms and fit them\n#############################################################################\n\n" + "Instantiate the different transport algorithms and fit them\n-----------------------------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -69,7 +69,7 @@ }, { "source": [ - "Fig 1 : plots source and target samples + matrix of pairwise distance\n#############################################################################\n\n" + "Fig 1 : plots source and target samples + matrix of pairwise distance\n---------------------------------------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -87,7 +87,7 @@ }, { "source": [ - "Fig 2 : plots optimal couplings for the different methods\n#############################################################################\n\n" + "Fig 2 : plots optimal couplings for the different methods\n---------------------------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -105,7 +105,7 @@ }, { "source": [ - "Fig 3 : plot transported samples\n#############################################################################\n\n" + "Fig 3 : plot transported samples\n--------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_otda_d2.py b/docs/source/auto_examples/plot_otda_d2.py index 3daa0a6..e53d7d6 100644 --- a/docs/source/auto_examples/plot_otda_d2.py +++ b/docs/source/auto_examples/plot_otda_d2.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- """ -============================== -OT for empirical distributions -============================== +=================================================== +OT for domain adaptation on empirical distributions +=================================================== This example introduces a domain adaptation in a 2D setting. It explicits the problem of domain adaptation and introduces some optimal transport @@ -24,7 +24,7 @@ import ot ############################################################################## # generate data -############################################################################## +# ------------- n_samples_source = 150 n_samples_target = 150 @@ -38,7 +38,7 @@ M = ot.dist(Xs, Xt, metric='sqeuclidean') ############################################################################## # Instantiate the different transport algorithms and fit them -############################################################################## +# ----------------------------------------------------------- # EMD Transport ot_emd = ot.da.EMDTransport() @@ -60,7 +60,7 @@ transp_Xs_lpl1 = ot_lpl1.transform(Xs=Xs) ############################################################################## # Fig 1 : plots source and target samples + matrix of pairwise distance -############################################################################## +# --------------------------------------------------------------------- pl.figure(1, figsize=(10, 10)) pl.subplot(2, 2, 1) @@ -87,8 +87,7 @@ pl.tight_layout() ############################################################################## # Fig 2 : plots optimal couplings for the different methods -############################################################################## - +# --------------------------------------------------------- pl.figure(2, figsize=(10, 6)) pl.subplot(2, 3, 1) @@ -137,7 +136,7 @@ pl.tight_layout() ############################################################################## # Fig 3 : plot transported samples -############################################################################## +# -------------------------------- # display transported samples pl.figure(4, figsize=(10, 4)) diff --git a/docs/source/auto_examples/plot_otda_d2.rst b/docs/source/auto_examples/plot_otda_d2.rst index 3aa1149..2b716e1 100644 --- a/docs/source/auto_examples/plot_otda_d2.rst +++ b/docs/source/auto_examples/plot_otda_d2.rst @@ -3,9 +3,9 @@ .. _sphx_glr_auto_examples_plot_otda_d2.py: -============================== -OT for empirical distributions -============================== +=================================================== +OT for domain adaptation on empirical distributions +=================================================== This example introduces a domain adaptation in a 2D setting. It explicits the problem of domain adaptation and introduces some optimal transport @@ -36,7 +36,7 @@ of what the transport methods are doing. generate data -############################################################################# +------------- @@ -60,7 +60,7 @@ generate data Instantiate the different transport algorithms and fit them -############################################################################# +----------------------------------------------------------- @@ -92,7 +92,7 @@ Instantiate the different transport algorithms and fit them Fig 1 : plots source and target samples + matrix of pairwise distance -############################################################################# +--------------------------------------------------------------------- @@ -132,13 +132,12 @@ Fig 1 : plots source and target samples + matrix of pairwise distance Fig 2 : plots optimal couplings for the different methods -############################################################################# +--------------------------------------------------------- .. code-block:: python - pl.figure(2, figsize=(10, 6)) pl.subplot(2, 3, 1) @@ -195,7 +194,7 @@ Fig 2 : plots optimal couplings for the different methods Fig 3 : plot transported samples -############################################################################# +-------------------------------- @@ -243,7 +242,7 @@ Fig 3 : plot transported samples -**Total running time of the script:** ( 0 minutes 32.275 seconds) +**Total running time of the script:** ( 0 minutes 32.084 seconds) diff --git a/docs/source/auto_examples/plot_otda_mapping.ipynb b/docs/source/auto_examples/plot_otda_mapping.ipynb index 5b3fd06..0374146 100644 --- a/docs/source/auto_examples/plot_otda_mapping.ipynb +++ b/docs/source/auto_examples/plot_otda_mapping.ipynb @@ -33,7 +33,7 @@ }, { "source": [ - "Generate data\n#############################################################################\n\n" + "Generate data\n-------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -51,7 +51,7 @@ }, { "source": [ - "Plot data\n#############################################################################\n\n" + "Plot data\n---------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -69,7 +69,7 @@ }, { "source": [ - "Instantiate the different transport algorithms and fit them\n#############################################################################\n\n" + "Instantiate the different transport algorithms and fit them\n-----------------------------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -87,7 +87,7 @@ }, { "source": [ - "Plot transported samples\n#############################################################################\n\n" + "Plot transported samples\n------------------------\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_otda_mapping.py b/docs/source/auto_examples/plot_otda_mapping.py index e78fef4..167c3a1 100644 --- a/docs/source/auto_examples/plot_otda_mapping.py +++ b/docs/source/auto_examples/plot_otda_mapping.py @@ -25,7 +25,7 @@ import ot ############################################################################## # Generate data -############################################################################## +# ------------- n_source_samples = 100 n_target_samples = 100 @@ -45,7 +45,7 @@ Xt = Xt + 4 ############################################################################## # Plot data -############################################################################## +# --------- pl.figure(1, (10, 5)) pl.clf() @@ -57,7 +57,7 @@ pl.title('Source and target distributions') ############################################################################## # Instantiate the different transport algorithms and fit them -############################################################################## +# ----------------------------------------------------------- # MappingTransport with linear kernel ot_mapping_linear = ot.da.MappingTransport( @@ -88,7 +88,7 @@ transp_Xs_gaussian_new = ot_mapping_gaussian.transform(Xs=Xs_new) ############################################################################## # Plot transported samples -############################################################################## +# ------------------------ pl.figure(2) pl.clf() diff --git a/docs/source/auto_examples/plot_otda_mapping.rst b/docs/source/auto_examples/plot_otda_mapping.rst index ddc1ee9..6c1c780 100644 --- a/docs/source/auto_examples/plot_otda_mapping.rst +++ b/docs/source/auto_examples/plot_otda_mapping.rst @@ -37,7 +37,7 @@ a linear or a kernelized mapping as introduced in [8]. Generate data -############################################################################# +------------- @@ -67,7 +67,7 @@ Generate data Plot data -############################################################################# +--------- @@ -92,7 +92,7 @@ Plot data Instantiate the different transport algorithms and fit them -############################################################################# +----------------------------------------------------------- @@ -136,30 +136,28 @@ Instantiate the different transport algorithms and fit them It. |Loss |Delta loss -------------------------------- - 0|4.481482e+03|0.000000e+00 - 1|4.469389e+03|-2.698549e-03 - 2|4.468825e+03|-1.261217e-04 - 3|4.468580e+03|-5.486064e-05 - 4|4.468438e+03|-3.161220e-05 - 5|4.468352e+03|-1.930800e-05 - 6|4.468309e+03|-9.570658e-06 + 0|4.307233e+03|0.000000e+00 + 1|4.296694e+03|-2.446759e-03 + 2|4.296419e+03|-6.417421e-05 + 3|4.296328e+03|-2.110209e-05 + 4|4.296305e+03|-5.298603e-06 It. |Loss |Delta loss -------------------------------- - 0|4.504654e+02|0.000000e+00 - 1|4.461571e+02|-9.564116e-03 - 2|4.459105e+02|-5.528043e-04 - 3|4.457895e+02|-2.712398e-04 - 4|4.457041e+02|-1.914829e-04 - 5|4.456431e+02|-1.369704e-04 - 6|4.456032e+02|-8.944784e-05 - 7|4.455700e+02|-7.447824e-05 - 8|4.455447e+02|-5.688965e-05 - 9|4.455229e+02|-4.890051e-05 - 10|4.455084e+02|-3.262490e-05 + 0|4.325624e+02|0.000000e+00 + 1|4.281958e+02|-1.009489e-02 + 2|4.279370e+02|-6.042202e-04 + 3|4.278109e+02|-2.947651e-04 + 4|4.277212e+02|-2.096651e-04 + 5|4.276589e+02|-1.456221e-04 + 6|4.276141e+02|-1.048476e-04 + 7|4.275803e+02|-7.906213e-05 + 8|4.275531e+02|-6.360573e-05 + 9|4.275314e+02|-5.076642e-05 + 10|4.275129e+02|-4.325858e-05 Plot transported samples -############################################################################# +------------------------ @@ -208,7 +206,7 @@ Plot transported samples -**Total running time of the script:** ( 0 minutes 0.869 seconds) +**Total running time of the script:** ( 0 minutes 0.747 seconds) diff --git a/docs/source/auto_examples/plot_otda_mapping_colors_images.ipynb b/docs/source/auto_examples/plot_otda_mapping_colors_images.ipynb index 3b3987a..56caa8a 100644 --- a/docs/source/auto_examples/plot_otda_mapping_colors_images.ipynb +++ b/docs/source/auto_examples/plot_otda_mapping_colors_images.ipynb @@ -33,7 +33,7 @@ }, { "source": [ - "Generate data\n#############################################################################\n\n" + "Generate data\n-------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -51,7 +51,7 @@ }, { "source": [ - "Domain adaptation for pixel distribution transfer\n#############################################################################\n\n" + "Domain adaptation for pixel distribution transfer\n-------------------------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -69,7 +69,7 @@ }, { "source": [ - "Plot original images\n#############################################################################\n\n" + "Plot original images\n--------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -87,7 +87,7 @@ }, { "source": [ - "Plot pixel values distribution\n#############################################################################\n\n" + "Plot pixel values distribution\n------------------------------\n\n" ], "cell_type": "markdown", "metadata": {} @@ -105,7 +105,7 @@ }, { "source": [ - "Plot transformed images\n#############################################################################\n\n" + "Plot transformed images\n-----------------------\n\n" ], "cell_type": "markdown", "metadata": {} diff --git a/docs/source/auto_examples/plot_otda_mapping_colors_images.py b/docs/source/auto_examples/plot_otda_mapping_colors_images.py index 5590286..5f1e844 100644 --- a/docs/source/auto_examples/plot_otda_mapping_colors_images.py +++ b/docs/source/auto_examples/plot_otda_mapping_colors_images.py @@ -45,7 +45,7 @@ def minmax(I): ############################################################################## # Generate data -############################################################################## +# ------------- # Loading images I1 = ndimage.imread('../data/ocean_day.jpg').astype(np.float64) / 256 @@ -66,7 +66,7 @@ Xt = X2[idx2, :] ############################################################################## # Domain adaptation for pixel distribution transfer -############################################################################## +# ------------------------------------------------- # EMDTransport ot_emd = ot.da.EMDTransport() @@ -97,7 +97,7 @@ Image_mapping_gaussian = minmax(mat2im(X1tn, I1.shape)) ############################################################################## # Plot original images -############################################################################## +# -------------------- pl.figure(1, figsize=(6.4, 3)) pl.subplot(1, 2, 1) @@ -114,7 +114,7 @@ pl.tight_layout() ############################################################################## # Plot pixel values distribution -############################################################################## +# ------------------------------ pl.figure(2, figsize=(6.4, 5)) @@ -136,7 +136,7 @@ pl.tight_layout() ############################################################################## # Plot transformed images -############################################################################## +# ----------------------- pl.figure(2, figsize=(10, 5)) diff --git a/docs/source/auto_examples/plot_otda_mapping_colors_images.rst b/docs/source/auto_examples/plot_otda_mapping_colors_images.rst index 9995103..86b1312 100644 --- a/docs/source/auto_examples/plot_otda_mapping_colors_images.rst +++ b/docs/source/auto_examples/plot_otda_mapping_colors_images.rst @@ -57,7 +57,7 @@ estimation [8]. Generate data -############################################################################# +------------- @@ -88,7 +88,7 @@ Generate data Domain adaptation for pixel distribution transfer -############################################################################# +------------------------------------------------- @@ -168,7 +168,7 @@ Domain adaptation for pixel distribution transfer Plot original images -############################################################################# +-------------------- @@ -198,7 +198,7 @@ Plot original images Plot pixel values distribution -############################################################################# +------------------------------ @@ -233,7 +233,7 @@ Plot pixel values distribution Plot transformed images -############################################################################# +----------------------- @@ -283,7 +283,7 @@ Plot transformed images -**Total running time of the script:** ( 2 minutes 8.746 seconds) +**Total running time of the script:** ( 2 minutes 5.213 seconds) diff --git a/docs/source/conf.py b/docs/source/conf.py index 0a822e5..156b878 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -33,7 +33,7 @@ class Mock(MagicMock): return MagicMock() MOCK_MODULES = ['ot.lp.emd_wrap','autograd','pymanopt','cudamat','autograd.numpy','pymanopt.manifolds','pymanopt.solvers'] # 'autograd.numpy','pymanopt.manifolds','pymanopt.solvers', -##sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES) +###sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES) # !!!! # If extensions (or modules to document with autodoc) are in another directory, -- cgit v1.2.3 From dd3546baf9c59733b2109a971293eba48d2eaed3 Mon Sep 17 00:00:00 2001 From: Rémi Flamary Date: Fri, 15 Sep 2017 13:57:01 +0200 Subject: add all files for doc --- docs/cache_nbrun | 2 +- .../source/auto_examples/auto_examples_jupyter.zip | Bin 67774 -> 89148 bytes docs/source/auto_examples/auto_examples_python.zip | Bin 44112 -> 59370 bytes .../images/sphx_glr_plot_gromov_001.png | Bin 0 -> 46633 bytes .../images/sphx_glr_plot_gromov_002.png | Bin 0 -> 16945 bytes .../images/sphx_glr_plot_gromov_003.png | Bin 0 -> 16530 bytes .../images/sphx_glr_plot_gromov_barycenter_001.png | Bin 0 -> 47537 bytes .../images/sphx_glr_plot_optim_OTreg_006.png | Bin 19189 -> 19258 bytes .../images/sphx_glr_plot_otda_classes_001.png | Bin 51418 -> 50899 bytes .../images/sphx_glr_plot_otda_classes_003.png | Bin 199721 -> 197590 bytes .../images/sphx_glr_plot_otda_color_images_001.png | Bin 144945 -> 144957 bytes .../images/sphx_glr_plot_otda_color_images_003.png | Bin 50403 -> 50401 bytes .../images/sphx_glr_plot_otda_color_images_005.png | Bin 234386 -> 234564 bytes .../images/sphx_glr_plot_otda_d2_001.png | Bin 135206 -> 131063 bytes .../images/sphx_glr_plot_otda_d2_003.png | Bin 241976 -> 213055 bytes .../images/sphx_glr_plot_otda_d2_006.png | Bin 108946 -> 99762 bytes .../images/sphx_glr_plot_otda_mapping_001.png | Bin 35881 -> 36766 bytes .../images/sphx_glr_plot_otda_mapping_003.png | Bin 73815 -> 75842 bytes ...phx_glr_plot_otda_mapping_colors_images_001.png | Bin 165589 -> 165592 bytes ...phx_glr_plot_otda_mapping_colors_images_003.png | Bin 80727 -> 80722 bytes ...phx_glr_plot_otda_mapping_colors_images_004.png | Bin 541463 -> 541314 bytes .../sphx_glr_plot_otda_semi_supervised_001.png | Bin 0 -> 153695 bytes .../sphx_glr_plot_otda_semi_supervised_003.png | Bin 0 -> 37987 bytes .../sphx_glr_plot_otda_semi_supervised_006.png | Bin 0 -> 74267 bytes .../thumb/sphx_glr_plot_otda_classes_thumb.png | Bin 30678 -> 30868 bytes .../sphx_glr_plot_otda_color_images_thumb.png | Bin 51088 -> 51085 bytes .../images/thumb/sphx_glr_plot_otda_d2_thumb.png | Bin 53014 -> 52743 bytes ...x_glr_plot_otda_mapping_colors_images_thumb.png | Bin 58321 -> 58315 bytes .../thumb/sphx_glr_plot_otda_mapping_thumb.png | Bin 18473 -> 18478 bytes docs/source/auto_examples/index.rst | 326 ++++++++++++++++++ docs/source/auto_examples/plot_gromov.ipynb | 126 +++++++ docs/source/auto_examples/plot_gromov.py | 93 +++++ docs/source/auto_examples/plot_gromov.rst | 180 ++++++++++ .../auto_examples/plot_gromov_barycenter.ipynb | 126 +++++++ .../source/auto_examples/plot_gromov_barycenter.py | 248 ++++++++++++++ .../auto_examples/plot_gromov_barycenter.rst | 324 ++++++++++++++++++ docs/source/auto_examples/plot_optim_OTreg.rst | 379 ++++++++++----------- docs/source/auto_examples/plot_otda_classes.rst | 46 +-- .../auto_examples/plot_otda_color_images.rst | 4 +- docs/source/auto_examples/plot_otda_d2.rst | 4 +- docs/source/auto_examples/plot_otda_mapping.rst | 38 ++- .../plot_otda_mapping_colors_images.rst | 66 ++-- .../auto_examples/plot_otda_semi_supervised.ipynb | 144 ++++++++ .../auto_examples/plot_otda_semi_supervised.py | 148 ++++++++ .../auto_examples/plot_otda_semi_supervised.rst | 240 +++++++++++++ docs/source/conf.py | 4 +- examples/plot_gromov.py | 40 +-- examples/plot_gromov_barycenter.py | 42 +-- examples/plot_otda_semi_supervised.py | 148 ++++++++ notebooks/plot_gromov.ipynb | 231 +++++++++++++ notebooks/plot_gromov_barycenter.ipynb | 368 ++++++++++++++++++++ notebooks/plot_otda_semi_supervised.ipynb | 294 ++++++++++++++++ 52 files changed, 3295 insertions(+), 326 deletions(-) create mode 100644 docs/source/auto_examples/images/sphx_glr_plot_gromov_001.png create mode 100644 docs/source/auto_examples/images/sphx_glr_plot_gromov_002.png create mode 100644 docs/source/auto_examples/images/sphx_glr_plot_gromov_003.png create mode 100644 docs/source/auto_examples/images/sphx_glr_plot_gromov_barycenter_001.png create mode 100644 docs/source/auto_examples/images/sphx_glr_plot_otda_semi_supervised_001.png create mode 100644 docs/source/auto_examples/images/sphx_glr_plot_otda_semi_supervised_003.png create mode 100644 docs/source/auto_examples/images/sphx_glr_plot_otda_semi_supervised_006.png create mode 100644 docs/source/auto_examples/plot_gromov.ipynb create mode 100644 docs/source/auto_examples/plot_gromov.py create mode 100644 docs/source/auto_examples/plot_gromov.rst create mode 100644 docs/source/auto_examples/plot_gromov_barycenter.ipynb create mode 100644 docs/source/auto_examples/plot_gromov_barycenter.py create mode 100644 docs/source/auto_examples/plot_gromov_barycenter.rst create mode 100644 docs/source/auto_examples/plot_otda_semi_supervised.ipynb create mode 100644 docs/source/auto_examples/plot_otda_semi_supervised.py create mode 100644 docs/source/auto_examples/plot_otda_semi_supervised.rst create mode 100644 examples/plot_otda_semi_supervised.py create mode 100644 notebooks/plot_gromov.ipynb create mode 100644 notebooks/plot_gromov_barycenter.ipynb create mode 100644 notebooks/plot_otda_semi_supervised.ipynb (limited to 'docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png') diff --git a/docs/cache_nbrun b/docs/cache_nbrun index ed1a660..3f1e6ea 100644 --- a/docs/cache_nbrun +++ b/docs/cache_nbrun @@ -1 +1 @@ -{"plot_otda_mapping_colors_images.ipynb": "4f0587a00a3c082799a75a0ed36e9ce1", "plot_optim_OTreg.ipynb": "71d3c106b3f395a6b1001078a6ca6f8d", "plot_otda_color_images.ipynb": "d047d635f4987c81072383241590e21f", "plot_WDA.ipynb": "27f8de4c6d7db46497076523673eedfb", "plot_OT_L1_vs_L2.ipynb": "e15219bf651a7e39e7c5c3934069894c", "plot_barycenter_1D.ipynb": "6fd8167f98816dc832fe0c58b1d5527b", "plot_otda_classes.ipynb": "44bb8cd93317b5d342cd62e26d9bbe60", "plot_otda_d2.ipynb": "8ac4fd2ff899df0858ce1e5fead37f33", "plot_otda_mapping.ipynb": "d335a15af828aaa3439a1c67570d79d6", "plot_gromov.ipynb": "f0c6d6431b270f042274de637bc0cb8c", "plot_compute_emd.ipynb": "bd95981189df6adcb113d9b360ead734", "plot_OT_1D.ipynb": "e44c83f6112388ae18657cb0ad76d0e9", "plot_OT_2D_samples.ipynb": "3f125714daa35ff3cfe5dae1f71265c4"} \ No newline at end of file +{"plot_otda_mapping_colors_images.ipynb": "4f0587a00a3c082799a75a0ed36e9ce1", "plot_optim_OTreg.ipynb": "71d3c106b3f395a6b1001078a6ca6f8d", "plot_otda_color_images.ipynb": "d047d635f4987c81072383241590e21f", "plot_WDA.ipynb": "27f8de4c6d7db46497076523673eedfb", "plot_OT_L1_vs_L2.ipynb": "e15219bf651a7e39e7c5c3934069894c", "plot_barycenter_1D.ipynb": "6fd8167f98816dc832fe0c58b1d5527b", "plot_otda_classes.ipynb": "44bb8cd93317b5d342cd62e26d9bbe60", "plot_otda_d2.ipynb": "8ac4fd2ff899df0858ce1e5fead37f33", "plot_otda_mapping.ipynb": "d335a15af828aaa3439a1c67570d79d6", "plot_gromov.ipynb": "9d0893ec68851f200d0ca806bcbe847f", "plot_compute_emd.ipynb": "bd95981189df6adcb113d9b360ead734", "plot_OT_1D.ipynb": "e44c83f6112388ae18657cb0ad76d0e9", "plot_gromov_barycenter.ipynb": "a4d9636685394ceb13f26cdc613b9b5b", "plot_otda_semi_supervised.ipynb": "0261d339a692e339e15d3634488905cc", "plot_OT_2D_samples.ipynb": "3f125714daa35ff3cfe5dae1f71265c4"} \ No newline at end of file diff --git a/docs/source/auto_examples/auto_examples_jupyter.zip b/docs/source/auto_examples/auto_examples_jupyter.zip index fc1d4de..5a3f24c 100644 Binary files a/docs/source/auto_examples/auto_examples_jupyter.zip and b/docs/source/auto_examples/auto_examples_jupyter.zip differ diff --git a/docs/source/auto_examples/auto_examples_python.zip b/docs/source/auto_examples/auto_examples_python.zip index 282bc58..aa06bb6 100644 Binary files a/docs/source/auto_examples/auto_examples_python.zip and b/docs/source/auto_examples/auto_examples_python.zip differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_gromov_001.png b/docs/source/auto_examples/images/sphx_glr_plot_gromov_001.png new file mode 100644 index 0000000..b4571fa Binary files /dev/null and b/docs/source/auto_examples/images/sphx_glr_plot_gromov_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_gromov_002.png b/docs/source/auto_examples/images/sphx_glr_plot_gromov_002.png new file mode 100644 index 0000000..58c02d7 Binary files /dev/null and b/docs/source/auto_examples/images/sphx_glr_plot_gromov_002.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_gromov_003.png b/docs/source/auto_examples/images/sphx_glr_plot_gromov_003.png new file mode 100644 index 0000000..73a322d Binary files /dev/null and b/docs/source/auto_examples/images/sphx_glr_plot_gromov_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_gromov_barycenter_001.png b/docs/source/auto_examples/images/sphx_glr_plot_gromov_barycenter_001.png new file mode 100644 index 0000000..715a116 Binary files /dev/null and b/docs/source/auto_examples/images/sphx_glr_plot_gromov_barycenter_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_optim_OTreg_006.png b/docs/source/auto_examples/images/sphx_glr_plot_optim_OTreg_006.png index 0af4542..60078c1 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_optim_OTreg_006.png and b/docs/source/auto_examples/images/sphx_glr_plot_optim_OTreg_006.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png index bedc950..48fad93 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_003.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_003.png index 8e3ccad..c92d5c1 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_classes_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_001.png index 2d851c7..95f882a 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_003.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_003.png index a1d99ab..aa1a5d3 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_005.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_005.png index f76619b..d219bb3 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_005.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_color_images_005.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_001.png index 3d6a740..ef8cfd1 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_003.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_003.png index aa16585..1ba5b1b 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_006.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_006.png index 5dc3ba7..d67fea1 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_006.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_d2_006.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_001.png index 4239465..8da464b 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_003.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_003.png index 620105e..fa93ee5 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_001.png index 1182082..33134fc 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_001.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_003.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_003.png index cc2e4cd..42197e3 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_003.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_004.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_004.png index 7a68343..d9101da 100644 Binary files a/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_004.png and b/docs/source/auto_examples/images/sphx_glr_plot_otda_mapping_colors_images_004.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_semi_supervised_001.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_semi_supervised_001.png new file mode 100644 index 0000000..324aee3 Binary files /dev/null and b/docs/source/auto_examples/images/sphx_glr_plot_otda_semi_supervised_001.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_semi_supervised_003.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_semi_supervised_003.png new file mode 100644 index 0000000..8ad6ca2 Binary files /dev/null and b/docs/source/auto_examples/images/sphx_glr_plot_otda_semi_supervised_003.png differ diff --git a/docs/source/auto_examples/images/sphx_glr_plot_otda_semi_supervised_006.png b/docs/source/auto_examples/images/sphx_glr_plot_otda_semi_supervised_006.png new file mode 100644 index 0000000..b4eacb7 Binary files /dev/null and b/docs/source/auto_examples/images/sphx_glr_plot_otda_semi_supervised_006.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png index a72fe37..561c5bb 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_color_images_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_color_images_thumb.png index 16b7572..a919055 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_color_images_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_color_images_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png index cddf768..bd32092 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_colors_images_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_colors_images_thumb.png index 9666955..f7fd217 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_colors_images_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_colors_images_thumb.png differ diff --git a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png index 959cc44..37d99bd 100644 Binary files a/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png and b/docs/source/auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png differ diff --git a/docs/source/auto_examples/index.rst b/docs/source/auto_examples/index.rst index e69de29..eb54ca8 100644 --- a/docs/source/auto_examples/index.rst +++ b/docs/source/auto_examples/index.rst @@ -0,0 +1,326 @@ +POT Examples +============ + +This is a gallery of all the POT example files. + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_OT_1D_thumb.png + + :ref:`sphx_glr_auto_examples_plot_OT_1D.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_OT_1D + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_optim_OTreg_thumb.png + + :ref:`sphx_glr_auto_examples_plot_optim_OTreg.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_optim_OTreg + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_gromov_thumb.png + + :ref:`sphx_glr_auto_examples_plot_gromov.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_gromov + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_OT_2D_samples_thumb.png + + :ref:`sphx_glr_auto_examples_plot_OT_2D_samples.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_OT_2D_samples + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_compute_emd_thumb.png + + :ref:`sphx_glr_auto_examples_plot_compute_emd.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_compute_emd + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_WDA_thumb.png + + :ref:`sphx_glr_auto_examples_plot_WDA.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_WDA + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_otda_color_images_thumb.png + + :ref:`sphx_glr_auto_examples_plot_otda_color_images.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_otda_color_images + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_barycenter_1D_thumb.png + + :ref:`sphx_glr_auto_examples_plot_barycenter_1D.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_barycenter_1D + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_otda_mapping_colors_images_thumb.png + + :ref:`sphx_glr_auto_examples_plot_otda_mapping_colors_images.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_otda_mapping_colors_images + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_otda_mapping_thumb.png + + :ref:`sphx_glr_auto_examples_plot_otda_mapping.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_otda_mapping + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_otda_semi_supervised_thumb.png + + :ref:`sphx_glr_auto_examples_plot_otda_semi_supervised.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_otda_semi_supervised + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_otda_classes_thumb.png + + :ref:`sphx_glr_auto_examples_plot_otda_classes.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_otda_classes + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_otda_d2_thumb.png + + :ref:`sphx_glr_auto_examples_plot_otda_d2.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_otda_d2 + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_OT_L1_vs_L2_thumb.png + + :ref:`sphx_glr_auto_examples_plot_OT_L1_vs_L2.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_OT_L1_vs_L2 + +.. raw:: html + +
+ +.. only:: html + + .. figure:: /auto_examples/images/thumb/sphx_glr_plot_gromov_barycenter_thumb.png + + :ref:`sphx_glr_auto_examples_plot_gromov_barycenter.py` + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/plot_gromov_barycenter +.. raw:: html + +
+ + + +.. container:: sphx-glr-footer + + + .. container:: sphx-glr-download + + :download:`Download all examples in Python source code: auto_examples_python.zip ` + + + + .. container:: sphx-glr-download + + :download:`Download all examples in Jupyter notebooks: auto_examples_jupyter.zip ` + +.. rst-class:: sphx-glr-signature + + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_gromov.ipynb b/docs/source/auto_examples/plot_gromov.ipynb new file mode 100644 index 0000000..865848e --- /dev/null +++ b/docs/source/auto_examples/plot_gromov.ipynb @@ -0,0 +1,126 @@ +{ + "nbformat_minor": 0, + "nbformat": 4, + "cells": [ + { + "execution_count": null, + "cell_type": "code", + "source": [ + "%matplotlib inline" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "\n# Gromov-Wasserstein example\n\n\nThis example is designed to show how to use the Gromov-Wassertsein distance\ncomputation in POT.\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "# Author: Erwan Vautier \r\n# Nicolas Courty \r\n#\r\n# License: MIT License\r\n\r\nimport scipy as sp\r\nimport numpy as np\r\nimport matplotlib.pylab as pl\r\nfrom mpl_toolkits.mplot3d import Axes3D # noqa\r\nimport ot" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Sample two Gaussian distributions (2D and 3D)\r\n ---------------------------------------------\r\n\r\n The Gromov-Wasserstein distance allows to compute distances with samples that\r\n do not belong to the same metric space. For demonstration purpose, we sample\r\n two Gaussian distributions in 2- and 3-dimensional spaces.\r\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "n_samples = 30 # nb samples\r\n\r\nmu_s = np.array([0, 0])\r\ncov_s = np.array([[1, 0], [0, 1]])\r\n\r\nmu_t = np.array([4, 4, 4])\r\ncov_t = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])\r\n\r\n\r\nxs = ot.datasets.get_2D_samples_gauss(n_samples, mu_s, cov_s)\r\nP = sp.linalg.sqrtm(cov_t)\r\nxt = np.random.randn(n_samples, 3).dot(P) + mu_t" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Plotting the distributions\r\n--------------------------\r\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "fig = pl.figure()\r\nax1 = fig.add_subplot(121)\r\nax1.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\r\nax2 = fig.add_subplot(122, projection='3d')\r\nax2.scatter(xt[:, 0], xt[:, 1], xt[:, 2], color='r')\r\npl.show()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Compute distance kernels, normalize them and then display\r\n---------------------------------------------------------\r\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "C1 = sp.spatial.distance.cdist(xs, xs)\r\nC2 = sp.spatial.distance.cdist(xt, xt)\r\n\r\nC1 /= C1.max()\r\nC2 /= C2.max()\r\n\r\npl.figure()\r\npl.subplot(121)\r\npl.imshow(C1)\r\npl.subplot(122)\r\npl.imshow(C2)\r\npl.show()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Compute Gromov-Wasserstein plans and distance\r\n---------------------------------------------\r\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "p = ot.unif(n_samples)\r\nq = ot.unif(n_samples)\r\n\r\ngw = ot.gromov_wasserstein(C1, C2, p, q, 'square_loss', epsilon=5e-4)\r\ngw_dist = ot.gromov_wasserstein2(C1, C2, p, q, 'square_loss', epsilon=5e-4)\r\n\r\nprint('Gromov-Wasserstein distances between the distribution: ' + str(gw_dist))\r\n\r\npl.figure()\r\npl.imshow(gw, cmap='jet')\r\npl.colorbar()\r\npl.show()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "name": "python2", + "language": "python" + }, + "language_info": { + "mimetype": "text/x-python", + "nbconvert_exporter": "python", + "name": "python", + "file_extension": ".py", + "version": "2.7.12", + "pygments_lexer": "ipython2", + "codemirror_mode": { + "version": 2, + "name": "ipython" + } + } + } +} \ No newline at end of file diff --git a/docs/source/auto_examples/plot_gromov.py b/docs/source/auto_examples/plot_gromov.py new file mode 100644 index 0000000..d3f724c --- /dev/null +++ b/docs/source/auto_examples/plot_gromov.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +""" +========================== +Gromov-Wasserstein example +========================== + +This example is designed to show how to use the Gromov-Wassertsein distance +computation in POT. +""" + +# Author: Erwan Vautier +# Nicolas Courty +# +# License: MIT License + +import scipy as sp +import numpy as np +import matplotlib.pylab as pl +from mpl_toolkits.mplot3d import Axes3D # noqa +import ot + + +############################################################################## +# Sample two Gaussian distributions (2D and 3D) +# --------------------------------------------- +# +# The Gromov-Wasserstein distance allows to compute distances with samples that +# do not belong to the same metric space. For demonstration purpose, we sample +# two Gaussian distributions in 2- and 3-dimensional spaces. + + +n_samples = 30 # nb samples + +mu_s = np.array([0, 0]) +cov_s = np.array([[1, 0], [0, 1]]) + +mu_t = np.array([4, 4, 4]) +cov_t = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + + +xs = ot.datasets.get_2D_samples_gauss(n_samples, mu_s, cov_s) +P = sp.linalg.sqrtm(cov_t) +xt = np.random.randn(n_samples, 3).dot(P) + mu_t + + +############################################################################## +# Plotting the distributions +# -------------------------- + + +fig = pl.figure() +ax1 = fig.add_subplot(121) +ax1.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') +ax2 = fig.add_subplot(122, projection='3d') +ax2.scatter(xt[:, 0], xt[:, 1], xt[:, 2], color='r') +pl.show() + + +############################################################################## +# Compute distance kernels, normalize them and then display +# --------------------------------------------------------- + + +C1 = sp.spatial.distance.cdist(xs, xs) +C2 = sp.spatial.distance.cdist(xt, xt) + +C1 /= C1.max() +C2 /= C2.max() + +pl.figure() +pl.subplot(121) +pl.imshow(C1) +pl.subplot(122) +pl.imshow(C2) +pl.show() + +############################################################################## +# Compute Gromov-Wasserstein plans and distance +# --------------------------------------------- + + +p = ot.unif(n_samples) +q = ot.unif(n_samples) + +gw = ot.gromov_wasserstein(C1, C2, p, q, 'square_loss', epsilon=5e-4) +gw_dist = ot.gromov_wasserstein2(C1, C2, p, q, 'square_loss', epsilon=5e-4) + +print('Gromov-Wasserstein distances between the distribution: ' + str(gw_dist)) + +pl.figure() +pl.imshow(gw, cmap='jet') +pl.colorbar() +pl.show() diff --git a/docs/source/auto_examples/plot_gromov.rst b/docs/source/auto_examples/plot_gromov.rst new file mode 100644 index 0000000..65cf4e4 --- /dev/null +++ b/docs/source/auto_examples/plot_gromov.rst @@ -0,0 +1,180 @@ + + +.. _sphx_glr_auto_examples_plot_gromov.py: + + +========================== +Gromov-Wasserstein example +========================== + +This example is designed to show how to use the Gromov-Wassertsein distance +computation in POT. + + + +.. code-block:: python + + + # Author: Erwan Vautier + # Nicolas Courty + # + # License: MIT License + + import scipy as sp + import numpy as np + import matplotlib.pylab as pl + from mpl_toolkits.mplot3d import Axes3D # noqa + import ot + + + + + + + + +Sample two Gaussian distributions (2D and 3D) + --------------------------------------------- + + The Gromov-Wasserstein distance allows to compute distances with samples that + do not belong to the same metric space. For demonstration purpose, we sample + two Gaussian distributions in 2- and 3-dimensional spaces. + + + +.. code-block:: python + + + + n_samples = 30 # nb samples + + mu_s = np.array([0, 0]) + cov_s = np.array([[1, 0], [0, 1]]) + + mu_t = np.array([4, 4, 4]) + cov_t = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + + + xs = ot.datasets.get_2D_samples_gauss(n_samples, mu_s, cov_s) + P = sp.linalg.sqrtm(cov_t) + xt = np.random.randn(n_samples, 3).dot(P) + mu_t + + + + + + + + +Plotting the distributions +-------------------------- + + + +.. code-block:: python + + + + fig = pl.figure() + ax1 = fig.add_subplot(121) + ax1.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') + ax2 = fig.add_subplot(122, projection='3d') + ax2.scatter(xt[:, 0], xt[:, 1], xt[:, 2], color='r') + pl.show() + + + + + +.. image:: /auto_examples/images/sphx_glr_plot_gromov_001.png + :align: center + + + + +Compute distance kernels, normalize them and then display +--------------------------------------------------------- + + + +.. code-block:: python + + + + C1 = sp.spatial.distance.cdist(xs, xs) + C2 = sp.spatial.distance.cdist(xt, xt) + + C1 /= C1.max() + C2 /= C2.max() + + pl.figure() + pl.subplot(121) + pl.imshow(C1) + pl.subplot(122) + pl.imshow(C2) + pl.show() + + + + +.. image:: /auto_examples/images/sphx_glr_plot_gromov_002.png + :align: center + + + + +Compute Gromov-Wasserstein plans and distance +--------------------------------------------- + + + +.. code-block:: python + + + + p = ot.unif(n_samples) + q = ot.unif(n_samples) + + gw = ot.gromov_wasserstein(C1, C2, p, q, 'square_loss', epsilon=5e-4) + gw_dist = ot.gromov_wasserstein2(C1, C2, p, q, 'square_loss', epsilon=5e-4) + + print('Gromov-Wasserstein distances between the distribution: ' + str(gw_dist)) + + pl.figure() + pl.imshow(gw, cmap='jet') + pl.colorbar() + pl.show() + + + +.. image:: /auto_examples/images/sphx_glr_plot_gromov_003.png + :align: center + + +.. rst-class:: sphx-glr-script-out + + Out:: + + Gromov-Wasserstein distances between the distribution: 0.225058076974 + + +**Total running time of the script:** ( 0 minutes 4.070 seconds) + + + +.. container:: sphx-glr-footer + + + .. container:: sphx-glr-download + + :download:`Download Python source code: plot_gromov.py ` + + + + .. container:: sphx-glr-download + + :download:`Download Jupyter notebook: plot_gromov.ipynb ` + +.. rst-class:: sphx-glr-signature + + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_gromov_barycenter.ipynb b/docs/source/auto_examples/plot_gromov_barycenter.ipynb new file mode 100644 index 0000000..d38dfbb --- /dev/null +++ b/docs/source/auto_examples/plot_gromov_barycenter.ipynb @@ -0,0 +1,126 @@ +{ + "nbformat_minor": 0, + "nbformat": 4, + "cells": [ + { + "execution_count": null, + "cell_type": "code", + "source": [ + "%matplotlib inline" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "\n# Gromov-Wasserstein Barycenter example\n\n\nThis example is designed to show how to use the Gromov-Wasserstein distance\ncomputation in POT.\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "# Author: Erwan Vautier \r\n# Nicolas Courty \r\n#\r\n# License: MIT License\r\n\r\n\r\nimport numpy as np\r\nimport scipy as sp\r\n\r\nimport scipy.ndimage as spi\r\nimport matplotlib.pylab as pl\r\nfrom sklearn import manifold\r\nfrom sklearn.decomposition import PCA\r\n\r\nimport ot" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Smacof MDS\r\n ----------\r\n\r\n This function allows to find an embedding of points given a dissimilarity matrix\r\n that will be given by the output of the algorithm\r\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "def smacof_mds(C, dim, max_iter=3000, eps=1e-9):\r\n \"\"\"\r\n Returns an interpolated point cloud following the dissimilarity matrix C\r\n using SMACOF multidimensional scaling (MDS) in specific dimensionned\r\n target space\r\n\r\n Parameters\r\n ----------\r\n C : ndarray, shape (ns, ns)\r\n dissimilarity matrix\r\n dim : int\r\n dimension of the targeted space\r\n max_iter : int\r\n Maximum number of iterations of the SMACOF algorithm for a single run\r\n eps : float\r\n relative tolerance w.r.t stress to declare converge\r\n\r\n Returns\r\n -------\r\n npos : ndarray, shape (R, dim)\r\n Embedded coordinates of the interpolated point cloud (defined with\r\n one isometry)\r\n \"\"\"\r\n\r\n rng = np.random.RandomState(seed=3)\r\n\r\n mds = manifold.MDS(\r\n dim,\r\n max_iter=max_iter,\r\n eps=1e-9,\r\n dissimilarity='precomputed',\r\n n_init=1)\r\n pos = mds.fit(C).embedding_\r\n\r\n nmds = manifold.MDS(\r\n 2,\r\n max_iter=max_iter,\r\n eps=1e-9,\r\n dissimilarity=\"precomputed\",\r\n random_state=rng,\r\n n_init=1)\r\n npos = nmds.fit_transform(C, init=pos)\r\n\r\n return npos" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Data preparation\r\n ----------------\r\n\r\n The four distributions are constructed from 4 simple images\r\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "def im2mat(I):\r\n \"\"\"Converts and image to matrix (one pixel per line)\"\"\"\r\n return I.reshape((I.shape[0] * I.shape[1], I.shape[2]))\r\n\r\n\r\nsquare = spi.imread('../data/square.png').astype(np.float64)[:, :, 2] / 256\r\ncross = spi.imread('../data/cross.png').astype(np.float64)[:, :, 2] / 256\r\ntriangle = spi.imread('../data/triangle.png').astype(np.float64)[:, :, 2] / 256\r\nstar = spi.imread('../data/star.png').astype(np.float64)[:, :, 2] / 256\r\n\r\nshapes = [square, cross, triangle, star]\r\n\r\nS = 4\r\nxs = [[] for i in range(S)]\r\n\r\n\r\nfor nb in range(4):\r\n for i in range(8):\r\n for j in range(8):\r\n if shapes[nb][i, j] < 0.95:\r\n xs[nb].append([j, 8 - i])\r\n\r\nxs = np.array([np.array(xs[0]), np.array(xs[1]),\r\n np.array(xs[2]), np.array(xs[3])])" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Barycenter computation\r\n----------------------\r\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "ns = [len(xs[s]) for s in range(S)]\r\nn_samples = 30\r\n\r\n\"\"\"Compute all distances matrices for the four shapes\"\"\"\r\nCs = [sp.spatial.distance.cdist(xs[s], xs[s]) for s in range(S)]\r\nCs = [cs / cs.max() for cs in Cs]\r\n\r\nps = [ot.unif(ns[s]) for s in range(S)]\r\np = ot.unif(n_samples)\r\n\r\n\r\nlambdast = [[float(i) / 3, float(3 - i) / 3] for i in [1, 2]]\r\n\r\nCt01 = [0 for i in range(2)]\r\nfor i in range(2):\r\n Ct01[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[0], Cs[1]],\r\n [ps[0], ps[1]\r\n ], p, lambdast[i], 'square_loss', 5e-4,\r\n max_iter=100, tol=1e-3)\r\n\r\nCt02 = [0 for i in range(2)]\r\nfor i in range(2):\r\n Ct02[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[0], Cs[2]],\r\n [ps[0], ps[2]\r\n ], p, lambdast[i], 'square_loss', 5e-4,\r\n max_iter=100, tol=1e-3)\r\n\r\nCt13 = [0 for i in range(2)]\r\nfor i in range(2):\r\n Ct13[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[1], Cs[3]],\r\n [ps[1], ps[3]\r\n ], p, lambdast[i], 'square_loss', 5e-4,\r\n max_iter=100, tol=1e-3)\r\n\r\nCt23 = [0 for i in range(2)]\r\nfor i in range(2):\r\n Ct23[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[2], Cs[3]],\r\n [ps[2], ps[3]\r\n ], p, lambdast[i], 'square_loss', 5e-4,\r\n max_iter=100, tol=1e-3)" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Visualization\r\n -------------\r\n\r\n The PCA helps in getting consistency between the rotations\r\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "clf = PCA(n_components=2)\r\nnpos = [0, 0, 0, 0]\r\nnpos = [smacof_mds(Cs[s], 2) for s in range(S)]\r\n\r\nnpost01 = [0, 0]\r\nnpost01 = [smacof_mds(Ct01[s], 2) for s in range(2)]\r\nnpost01 = [clf.fit_transform(npost01[s]) for s in range(2)]\r\n\r\nnpost02 = [0, 0]\r\nnpost02 = [smacof_mds(Ct02[s], 2) for s in range(2)]\r\nnpost02 = [clf.fit_transform(npost02[s]) for s in range(2)]\r\n\r\nnpost13 = [0, 0]\r\nnpost13 = [smacof_mds(Ct13[s], 2) for s in range(2)]\r\nnpost13 = [clf.fit_transform(npost13[s]) for s in range(2)]\r\n\r\nnpost23 = [0, 0]\r\nnpost23 = [smacof_mds(Ct23[s], 2) for s in range(2)]\r\nnpost23 = [clf.fit_transform(npost23[s]) for s in range(2)]\r\n\r\n\r\nfig = pl.figure(figsize=(10, 10))\r\n\r\nax1 = pl.subplot2grid((4, 4), (0, 0))\r\npl.xlim((-1, 1))\r\npl.ylim((-1, 1))\r\nax1.scatter(npos[0][:, 0], npos[0][:, 1], color='r')\r\n\r\nax2 = pl.subplot2grid((4, 4), (0, 1))\r\npl.xlim((-1, 1))\r\npl.ylim((-1, 1))\r\nax2.scatter(npost01[1][:, 0], npost01[1][:, 1], color='b')\r\n\r\nax3 = pl.subplot2grid((4, 4), (0, 2))\r\npl.xlim((-1, 1))\r\npl.ylim((-1, 1))\r\nax3.scatter(npost01[0][:, 0], npost01[0][:, 1], color='b')\r\n\r\nax4 = pl.subplot2grid((4, 4), (0, 3))\r\npl.xlim((-1, 1))\r\npl.ylim((-1, 1))\r\nax4.scatter(npos[1][:, 0], npos[1][:, 1], color='r')\r\n\r\nax5 = pl.subplot2grid((4, 4), (1, 0))\r\npl.xlim((-1, 1))\r\npl.ylim((-1, 1))\r\nax5.scatter(npost02[1][:, 0], npost02[1][:, 1], color='b')\r\n\r\nax6 = pl.subplot2grid((4, 4), (1, 3))\r\npl.xlim((-1, 1))\r\npl.ylim((-1, 1))\r\nax6.scatter(npost13[1][:, 0], npost13[1][:, 1], color='b')\r\n\r\nax7 = pl.subplot2grid((4, 4), (2, 0))\r\npl.xlim((-1, 1))\r\npl.ylim((-1, 1))\r\nax7.scatter(npost02[0][:, 0], npost02[0][:, 1], color='b')\r\n\r\nax8 = pl.subplot2grid((4, 4), (2, 3))\r\npl.xlim((-1, 1))\r\npl.ylim((-1, 1))\r\nax8.scatter(npost13[0][:, 0], npost13[0][:, 1], color='b')\r\n\r\nax9 = pl.subplot2grid((4, 4), (3, 0))\r\npl.xlim((-1, 1))\r\npl.ylim((-1, 1))\r\nax9.scatter(npos[2][:, 0], npos[2][:, 1], color='r')\r\n\r\nax10 = pl.subplot2grid((4, 4), (3, 1))\r\npl.xlim((-1, 1))\r\npl.ylim((-1, 1))\r\nax10.scatter(npost23[1][:, 0], npost23[1][:, 1], color='b')\r\n\r\nax11 = pl.subplot2grid((4, 4), (3, 2))\r\npl.xlim((-1, 1))\r\npl.ylim((-1, 1))\r\nax11.scatter(npost23[0][:, 0], npost23[0][:, 1], color='b')\r\n\r\nax12 = pl.subplot2grid((4, 4), (3, 3))\r\npl.xlim((-1, 1))\r\npl.ylim((-1, 1))\r\nax12.scatter(npos[3][:, 0], npos[3][:, 1], color='r')" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "name": "python2", + "language": "python" + }, + "language_info": { + "mimetype": "text/x-python", + "nbconvert_exporter": "python", + "name": "python", + "file_extension": ".py", + "version": "2.7.12", + "pygments_lexer": "ipython2", + "codemirror_mode": { + "version": 2, + "name": "ipython" + } + } + } +} \ No newline at end of file diff --git a/docs/source/auto_examples/plot_gromov_barycenter.py b/docs/source/auto_examples/plot_gromov_barycenter.py new file mode 100644 index 0000000..180b0cf --- /dev/null +++ b/docs/source/auto_examples/plot_gromov_barycenter.py @@ -0,0 +1,248 @@ +# -*- coding: utf-8 -*- +""" +===================================== +Gromov-Wasserstein Barycenter example +===================================== + +This example is designed to show how to use the Gromov-Wasserstein distance +computation in POT. +""" + +# Author: Erwan Vautier +# Nicolas Courty +# +# License: MIT License + + +import numpy as np +import scipy as sp + +import scipy.ndimage as spi +import matplotlib.pylab as pl +from sklearn import manifold +from sklearn.decomposition import PCA + +import ot + +############################################################################## +# Smacof MDS +# ---------- +# +# This function allows to find an embedding of points given a dissimilarity matrix +# that will be given by the output of the algorithm + + +def smacof_mds(C, dim, max_iter=3000, eps=1e-9): + """ + Returns an interpolated point cloud following the dissimilarity matrix C + using SMACOF multidimensional scaling (MDS) in specific dimensionned + target space + + Parameters + ---------- + C : ndarray, shape (ns, ns) + dissimilarity matrix + dim : int + dimension of the targeted space + max_iter : int + Maximum number of iterations of the SMACOF algorithm for a single run + eps : float + relative tolerance w.r.t stress to declare converge + + Returns + ------- + npos : ndarray, shape (R, dim) + Embedded coordinates of the interpolated point cloud (defined with + one isometry) + """ + + rng = np.random.RandomState(seed=3) + + mds = manifold.MDS( + dim, + max_iter=max_iter, + eps=1e-9, + dissimilarity='precomputed', + n_init=1) + pos = mds.fit(C).embedding_ + + nmds = manifold.MDS( + 2, + max_iter=max_iter, + eps=1e-9, + dissimilarity="precomputed", + random_state=rng, + n_init=1) + npos = nmds.fit_transform(C, init=pos) + + return npos + + +############################################################################## +# Data preparation +# ---------------- +# +# The four distributions are constructed from 4 simple images + + +def im2mat(I): + """Converts and image to matrix (one pixel per line)""" + return I.reshape((I.shape[0] * I.shape[1], I.shape[2])) + + +square = spi.imread('../data/square.png').astype(np.float64)[:, :, 2] / 256 +cross = spi.imread('../data/cross.png').astype(np.float64)[:, :, 2] / 256 +triangle = spi.imread('../data/triangle.png').astype(np.float64)[:, :, 2] / 256 +star = spi.imread('../data/star.png').astype(np.float64)[:, :, 2] / 256 + +shapes = [square, cross, triangle, star] + +S = 4 +xs = [[] for i in range(S)] + + +for nb in range(4): + for i in range(8): + for j in range(8): + if shapes[nb][i, j] < 0.95: + xs[nb].append([j, 8 - i]) + +xs = np.array([np.array(xs[0]), np.array(xs[1]), + np.array(xs[2]), np.array(xs[3])]) + +############################################################################## +# Barycenter computation +# ---------------------- + + +ns = [len(xs[s]) for s in range(S)] +n_samples = 30 + +"""Compute all distances matrices for the four shapes""" +Cs = [sp.spatial.distance.cdist(xs[s], xs[s]) for s in range(S)] +Cs = [cs / cs.max() for cs in Cs] + +ps = [ot.unif(ns[s]) for s in range(S)] +p = ot.unif(n_samples) + + +lambdast = [[float(i) / 3, float(3 - i) / 3] for i in [1, 2]] + +Ct01 = [0 for i in range(2)] +for i in range(2): + Ct01[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[0], Cs[1]], + [ps[0], ps[1] + ], p, lambdast[i], 'square_loss', 5e-4, + max_iter=100, tol=1e-3) + +Ct02 = [0 for i in range(2)] +for i in range(2): + Ct02[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[0], Cs[2]], + [ps[0], ps[2] + ], p, lambdast[i], 'square_loss', 5e-4, + max_iter=100, tol=1e-3) + +Ct13 = [0 for i in range(2)] +for i in range(2): + Ct13[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[1], Cs[3]], + [ps[1], ps[3] + ], p, lambdast[i], 'square_loss', 5e-4, + max_iter=100, tol=1e-3) + +Ct23 = [0 for i in range(2)] +for i in range(2): + Ct23[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[2], Cs[3]], + [ps[2], ps[3] + ], p, lambdast[i], 'square_loss', 5e-4, + max_iter=100, tol=1e-3) + + +############################################################################## +# Visualization +# ------------- +# +# The PCA helps in getting consistency between the rotations + + +clf = PCA(n_components=2) +npos = [0, 0, 0, 0] +npos = [smacof_mds(Cs[s], 2) for s in range(S)] + +npost01 = [0, 0] +npost01 = [smacof_mds(Ct01[s], 2) for s in range(2)] +npost01 = [clf.fit_transform(npost01[s]) for s in range(2)] + +npost02 = [0, 0] +npost02 = [smacof_mds(Ct02[s], 2) for s in range(2)] +npost02 = [clf.fit_transform(npost02[s]) for s in range(2)] + +npost13 = [0, 0] +npost13 = [smacof_mds(Ct13[s], 2) for s in range(2)] +npost13 = [clf.fit_transform(npost13[s]) for s in range(2)] + +npost23 = [0, 0] +npost23 = [smacof_mds(Ct23[s], 2) for s in range(2)] +npost23 = [clf.fit_transform(npost23[s]) for s in range(2)] + + +fig = pl.figure(figsize=(10, 10)) + +ax1 = pl.subplot2grid((4, 4), (0, 0)) +pl.xlim((-1, 1)) +pl.ylim((-1, 1)) +ax1.scatter(npos[0][:, 0], npos[0][:, 1], color='r') + +ax2 = pl.subplot2grid((4, 4), (0, 1)) +pl.xlim((-1, 1)) +pl.ylim((-1, 1)) +ax2.scatter(npost01[1][:, 0], npost01[1][:, 1], color='b') + +ax3 = pl.subplot2grid((4, 4), (0, 2)) +pl.xlim((-1, 1)) +pl.ylim((-1, 1)) +ax3.scatter(npost01[0][:, 0], npost01[0][:, 1], color='b') + +ax4 = pl.subplot2grid((4, 4), (0, 3)) +pl.xlim((-1, 1)) +pl.ylim((-1, 1)) +ax4.scatter(npos[1][:, 0], npos[1][:, 1], color='r') + +ax5 = pl.subplot2grid((4, 4), (1, 0)) +pl.xlim((-1, 1)) +pl.ylim((-1, 1)) +ax5.scatter(npost02[1][:, 0], npost02[1][:, 1], color='b') + +ax6 = pl.subplot2grid((4, 4), (1, 3)) +pl.xlim((-1, 1)) +pl.ylim((-1, 1)) +ax6.scatter(npost13[1][:, 0], npost13[1][:, 1], color='b') + +ax7 = pl.subplot2grid((4, 4), (2, 0)) +pl.xlim((-1, 1)) +pl.ylim((-1, 1)) +ax7.scatter(npost02[0][:, 0], npost02[0][:, 1], color='b') + +ax8 = pl.subplot2grid((4, 4), (2, 3)) +pl.xlim((-1, 1)) +pl.ylim((-1, 1)) +ax8.scatter(npost13[0][:, 0], npost13[0][:, 1], color='b') + +ax9 = pl.subplot2grid((4, 4), (3, 0)) +pl.xlim((-1, 1)) +pl.ylim((-1, 1)) +ax9.scatter(npos[2][:, 0], npos[2][:, 1], color='r') + +ax10 = pl.subplot2grid((4, 4), (3, 1)) +pl.xlim((-1, 1)) +pl.ylim((-1, 1)) +ax10.scatter(npost23[1][:, 0], npost23[1][:, 1], color='b') + +ax11 = pl.subplot2grid((4, 4), (3, 2)) +pl.xlim((-1, 1)) +pl.ylim((-1, 1)) +ax11.scatter(npost23[0][:, 0], npost23[0][:, 1], color='b') + +ax12 = pl.subplot2grid((4, 4), (3, 3)) +pl.xlim((-1, 1)) +pl.ylim((-1, 1)) +ax12.scatter(npos[3][:, 0], npos[3][:, 1], color='r') diff --git a/docs/source/auto_examples/plot_gromov_barycenter.rst b/docs/source/auto_examples/plot_gromov_barycenter.rst new file mode 100644 index 0000000..ca2d4e9 --- /dev/null +++ b/docs/source/auto_examples/plot_gromov_barycenter.rst @@ -0,0 +1,324 @@ + + +.. _sphx_glr_auto_examples_plot_gromov_barycenter.py: + + +===================================== +Gromov-Wasserstein Barycenter example +===================================== + +This example is designed to show how to use the Gromov-Wasserstein distance +computation in POT. + + + +.. code-block:: python + + + # Author: Erwan Vautier + # Nicolas Courty + # + # License: MIT License + + + import numpy as np + import scipy as sp + + import scipy.ndimage as spi + import matplotlib.pylab as pl + from sklearn import manifold + from sklearn.decomposition import PCA + + import ot + + + + + + + +Smacof MDS + ---------- + + This function allows to find an embedding of points given a dissimilarity matrix + that will be given by the output of the algorithm + + + +.. code-block:: python + + + + def smacof_mds(C, dim, max_iter=3000, eps=1e-9): + """ + Returns an interpolated point cloud following the dissimilarity matrix C + using SMACOF multidimensional scaling (MDS) in specific dimensionned + target space + + Parameters + ---------- + C : ndarray, shape (ns, ns) + dissimilarity matrix + dim : int + dimension of the targeted space + max_iter : int + Maximum number of iterations of the SMACOF algorithm for a single run + eps : float + relative tolerance w.r.t stress to declare converge + + Returns + ------- + npos : ndarray, shape (R, dim) + Embedded coordinates of the interpolated point cloud (defined with + one isometry) + """ + + rng = np.random.RandomState(seed=3) + + mds = manifold.MDS( + dim, + max_iter=max_iter, + eps=1e-9, + dissimilarity='precomputed', + n_init=1) + pos = mds.fit(C).embedding_ + + nmds = manifold.MDS( + 2, + max_iter=max_iter, + eps=1e-9, + dissimilarity="precomputed", + random_state=rng, + n_init=1) + npos = nmds.fit_transform(C, init=pos) + + return npos + + + + + + + + +Data preparation + ---------------- + + The four distributions are constructed from 4 simple images + + + +.. code-block:: python + + + + def im2mat(I): + """Converts and image to matrix (one pixel per line)""" + return I.reshape((I.shape[0] * I.shape[1], I.shape[2])) + + + square = spi.imread('../data/square.png').astype(np.float64)[:, :, 2] / 256 + cross = spi.imread('../data/cross.png').astype(np.float64)[:, :, 2] / 256 + triangle = spi.imread('../data/triangle.png').astype(np.float64)[:, :, 2] / 256 + star = spi.imread('../data/star.png').astype(np.float64)[:, :, 2] / 256 + + shapes = [square, cross, triangle, star] + + S = 4 + xs = [[] for i in range(S)] + + + for nb in range(4): + for i in range(8): + for j in range(8): + if shapes[nb][i, j] < 0.95: + xs[nb].append([j, 8 - i]) + + xs = np.array([np.array(xs[0]), np.array(xs[1]), + np.array(xs[2]), np.array(xs[3])]) + + + + + + + +Barycenter computation +---------------------- + + + +.. code-block:: python + + + + ns = [len(xs[s]) for s in range(S)] + n_samples = 30 + + """Compute all distances matrices for the four shapes""" + Cs = [sp.spatial.distance.cdist(xs[s], xs[s]) for s in range(S)] + Cs = [cs / cs.max() for cs in Cs] + + ps = [ot.unif(ns[s]) for s in range(S)] + p = ot.unif(n_samples) + + + lambdast = [[float(i) / 3, float(3 - i) / 3] for i in [1, 2]] + + Ct01 = [0 for i in range(2)] + for i in range(2): + Ct01[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[0], Cs[1]], + [ps[0], ps[1] + ], p, lambdast[i], 'square_loss', 5e-4, + max_iter=100, tol=1e-3) + + Ct02 = [0 for i in range(2)] + for i in range(2): + Ct02[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[0], Cs[2]], + [ps[0], ps[2] + ], p, lambdast[i], 'square_loss', 5e-4, + max_iter=100, tol=1e-3) + + Ct13 = [0 for i in range(2)] + for i in range(2): + Ct13[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[1], Cs[3]], + [ps[1], ps[3] + ], p, lambdast[i], 'square_loss', 5e-4, + max_iter=100, tol=1e-3) + + Ct23 = [0 for i in range(2)] + for i in range(2): + Ct23[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[2], Cs[3]], + [ps[2], ps[3] + ], p, lambdast[i], 'square_loss', 5e-4, + max_iter=100, tol=1e-3) + + + + + + + + +Visualization + ------------- + + The PCA helps in getting consistency between the rotations + + + +.. code-block:: python + + + + clf = PCA(n_components=2) + npos = [0, 0, 0, 0] + npos = [smacof_mds(Cs[s], 2) for s in range(S)] + + npost01 = [0, 0] + npost01 = [smacof_mds(Ct01[s], 2) for s in range(2)] + npost01 = [clf.fit_transform(npost01[s]) for s in range(2)] + + npost02 = [0, 0] + npost02 = [smacof_mds(Ct02[s], 2) for s in range(2)] + npost02 = [clf.fit_transform(npost02[s]) for s in range(2)] + + npost13 = [0, 0] + npost13 = [smacof_mds(Ct13[s], 2) for s in range(2)] + npost13 = [clf.fit_transform(npost13[s]) for s in range(2)] + + npost23 = [0, 0] + npost23 = [smacof_mds(Ct23[s], 2) for s in range(2)] + npost23 = [clf.fit_transform(npost23[s]) for s in range(2)] + + + fig = pl.figure(figsize=(10, 10)) + + ax1 = pl.subplot2grid((4, 4), (0, 0)) + pl.xlim((-1, 1)) + pl.ylim((-1, 1)) + ax1.scatter(npos[0][:, 0], npos[0][:, 1], color='r') + + ax2 = pl.subplot2grid((4, 4), (0, 1)) + pl.xlim((-1, 1)) + pl.ylim((-1, 1)) + ax2.scatter(npost01[1][:, 0], npost01[1][:, 1], color='b') + + ax3 = pl.subplot2grid((4, 4), (0, 2)) + pl.xlim((-1, 1)) + pl.ylim((-1, 1)) + ax3.scatter(npost01[0][:, 0], npost01[0][:, 1], color='b') + + ax4 = pl.subplot2grid((4, 4), (0, 3)) + pl.xlim((-1, 1)) + pl.ylim((-1, 1)) + ax4.scatter(npos[1][:, 0], npos[1][:, 1], color='r') + + ax5 = pl.subplot2grid((4, 4), (1, 0)) + pl.xlim((-1, 1)) + pl.ylim((-1, 1)) + ax5.scatter(npost02[1][:, 0], npost02[1][:, 1], color='b') + + ax6 = pl.subplot2grid((4, 4), (1, 3)) + pl.xlim((-1, 1)) + pl.ylim((-1, 1)) + ax6.scatter(npost13[1][:, 0], npost13[1][:, 1], color='b') + + ax7 = pl.subplot2grid((4, 4), (2, 0)) + pl.xlim((-1, 1)) + pl.ylim((-1, 1)) + ax7.scatter(npost02[0][:, 0], npost02[0][:, 1], color='b') + + ax8 = pl.subplot2grid((4, 4), (2, 3)) + pl.xlim((-1, 1)) + pl.ylim((-1, 1)) + ax8.scatter(npost13[0][:, 0], npost13[0][:, 1], color='b') + + ax9 = pl.subplot2grid((4, 4), (3, 0)) + pl.xlim((-1, 1)) + pl.ylim((-1, 1)) + ax9.scatter(npos[2][:, 0], npos[2][:, 1], color='r') + + ax10 = pl.subplot2grid((4, 4), (3, 1)) + pl.xlim((-1, 1)) + pl.ylim((-1, 1)) + ax10.scatter(npost23[1][:, 0], npost23[1][:, 1], color='b') + + ax11 = pl.subplot2grid((4, 4), (3, 2)) + pl.xlim((-1, 1)) + pl.ylim((-1, 1)) + ax11.scatter(npost23[0][:, 0], npost23[0][:, 1], color='b') + + ax12 = pl.subplot2grid((4, 4), (3, 3)) + pl.xlim((-1, 1)) + pl.ylim((-1, 1)) + ax12.scatter(npos[3][:, 0], npos[3][:, 1], color='r') + + + +.. image:: /auto_examples/images/sphx_glr_plot_gromov_barycenter_001.png + :align: center + + + + +**Total running time of the script:** ( 8 minutes 43.875 seconds) + + + +.. container:: sphx-glr-footer + + + .. container:: sphx-glr-download + + :download:`Download Python source code: plot_gromov_barycenter.py ` + + + + .. container:: sphx-glr-download + + :download:`Download Jupyter notebook: plot_gromov_barycenter.ipynb ` + +.. rst-class:: sphx-glr-signature + + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_optim_OTreg.rst b/docs/source/auto_examples/plot_optim_OTreg.rst index f628024..480149a 100644 --- a/docs/source/auto_examples/plot_optim_OTreg.rst +++ b/docs/source/auto_examples/plot_optim_OTreg.rst @@ -399,225 +399,194 @@ Solve EMD with entropic regularization -------------------------------- 0|1.692289e-01|0.000000e+00 1|1.617643e-01|-4.614437e-02 - 2|1.612546e-01|-3.161037e-03 - 3|1.611040e-01|-9.349544e-04 - 4|1.610346e-01|-4.310179e-04 - 5|1.610072e-01|-1.701719e-04 - 6|1.609947e-01|-7.759814e-05 - 7|1.609934e-01|-7.941439e-06 - 8|1.609841e-01|-5.797180e-05 - 9|1.609838e-01|-1.559407e-06 - 10|1.609685e-01|-9.530282e-05 - 11|1.609666e-01|-1.142129e-05 - 12|1.609541e-01|-7.799970e-05 - 13|1.609496e-01|-2.780416e-05 - 14|1.609385e-01|-6.887105e-05 - 15|1.609334e-01|-3.174241e-05 - 16|1.609231e-01|-6.420777e-05 - 17|1.609115e-01|-7.189949e-05 - 18|1.608815e-01|-1.865331e-04 - 19|1.608799e-01|-1.013039e-05 + 2|1.612639e-01|-3.102965e-03 + 3|1.611291e-01|-8.371098e-04 + 4|1.610468e-01|-5.110558e-04 + 5|1.610198e-01|-1.672927e-04 + 6|1.610130e-01|-4.232417e-05 + 7|1.610090e-01|-2.513455e-05 + 8|1.610002e-01|-5.443507e-05 + 9|1.609996e-01|-3.657071e-06 + 10|1.609948e-01|-2.998735e-05 + 11|1.609695e-01|-1.569217e-04 + 12|1.609533e-01|-1.010779e-04 + 13|1.609520e-01|-8.043897e-06 + 14|1.609465e-01|-3.415246e-05 + 15|1.609386e-01|-4.898605e-05 + 16|1.609324e-01|-3.837052e-05 + 17|1.609298e-01|-1.617826e-05 + 18|1.609184e-01|-7.080015e-05 + 19|1.609083e-01|-6.273206e-05 It. |Loss |Delta loss -------------------------------- - 20|1.608695e-01|-6.468606e-05 - 21|1.608686e-01|-5.738419e-06 - 22|1.608661e-01|-1.495923e-05 - 23|1.608657e-01|-2.784611e-06 - 24|1.608633e-01|-1.512408e-05 - 25|1.608624e-01|-5.397916e-06 - 26|1.608617e-01|-4.115218e-06 - 27|1.608561e-01|-3.503396e-05 - 28|1.608479e-01|-5.098773e-05 - 29|1.608452e-01|-1.659203e-05 - 30|1.608399e-01|-3.298319e-05 - 31|1.608330e-01|-4.302183e-05 - 32|1.608310e-01|-1.273465e-05 - 33|1.608280e-01|-1.827713e-05 - 34|1.608231e-01|-3.039842e-05 - 35|1.608212e-01|-1.229256e-05 - 36|1.608200e-01|-6.900556e-06 - 37|1.608159e-01|-2.554039e-05 - 38|1.608103e-01|-3.521137e-05 - 39|1.608058e-01|-2.795180e-05 + 20|1.608988e-01|-5.940805e-05 + 21|1.608853e-01|-8.380030e-05 + 22|1.608844e-01|-5.185045e-06 + 23|1.608824e-01|-1.279113e-05 + 24|1.608819e-01|-3.156821e-06 + 25|1.608783e-01|-2.205746e-05 + 26|1.608764e-01|-1.189894e-05 + 27|1.608755e-01|-5.474607e-06 + 28|1.608737e-01|-1.144227e-05 + 29|1.608676e-01|-3.775335e-05 + 30|1.608638e-01|-2.348020e-05 + 31|1.608627e-01|-6.863136e-06 + 32|1.608529e-01|-6.110230e-05 + 33|1.608487e-01|-2.641106e-05 + 34|1.608409e-01|-4.823638e-05 + 35|1.608373e-01|-2.256641e-05 + 36|1.608338e-01|-2.132444e-05 + 37|1.608310e-01|-1.786649e-05 + 38|1.608260e-01|-3.103848e-05 + 39|1.608206e-01|-3.321265e-05 It. |Loss |Delta loss -------------------------------- - 40|1.608040e-01|-1.119118e-05 - 41|1.608027e-01|-8.193369e-06 - 42|1.607994e-01|-2.026719e-05 - 43|1.607985e-01|-5.819902e-06 - 44|1.607978e-01|-4.048170e-06 - 45|1.607978e-01|-3.007470e-07 - 46|1.607950e-01|-1.705375e-05 - 47|1.607927e-01|-1.430186e-05 - 48|1.607925e-01|-1.166526e-06 - 49|1.607911e-01|-9.069406e-06 - 50|1.607910e-01|-3.804209e-07 - 51|1.607910e-01|-5.942399e-08 - 52|1.607910e-01|-2.321380e-07 - 53|1.607907e-01|-1.877655e-06 - 54|1.607906e-01|-2.940224e-07 - 55|1.607877e-01|-1.814208e-05 - 56|1.607841e-01|-2.236496e-05 - 57|1.607810e-01|-1.951355e-05 - 58|1.607804e-01|-3.578228e-06 - 59|1.607789e-01|-9.442277e-06 + 40|1.608201e-01|-3.054747e-06 + 41|1.608195e-01|-4.198335e-06 + 42|1.608193e-01|-8.458736e-07 + 43|1.608159e-01|-2.153759e-05 + 44|1.608115e-01|-2.738314e-05 + 45|1.608108e-01|-3.960032e-06 + 46|1.608081e-01|-1.675447e-05 + 47|1.608072e-01|-5.976340e-06 + 48|1.608046e-01|-1.604130e-05 + 49|1.608020e-01|-1.617036e-05 + 50|1.608014e-01|-3.957795e-06 + 51|1.608011e-01|-1.292411e-06 + 52|1.607998e-01|-8.431795e-06 + 53|1.607964e-01|-2.127054e-05 + 54|1.607947e-01|-1.021878e-05 + 55|1.607947e-01|-3.560621e-07 + 56|1.607900e-01|-2.929781e-05 + 57|1.607890e-01|-5.740229e-06 + 58|1.607858e-01|-2.039550e-05 + 59|1.607836e-01|-1.319545e-05 It. |Loss |Delta loss -------------------------------- - 60|1.607779e-01|-5.997371e-06 - 61|1.607754e-01|-1.564408e-05 - 62|1.607742e-01|-7.693285e-06 - 63|1.607727e-01|-9.030547e-06 - 64|1.607719e-01|-5.103894e-06 - 65|1.607693e-01|-1.605420e-05 - 66|1.607676e-01|-1.047837e-05 - 67|1.607675e-01|-6.026848e-07 - 68|1.607655e-01|-1.240216e-05 - 69|1.607632e-01|-1.434674e-05 - 70|1.607618e-01|-8.829808e-06 - 71|1.607606e-01|-7.581824e-06 - 72|1.607590e-01|-1.009457e-05 - 73|1.607586e-01|-2.222963e-06 - 74|1.607577e-01|-5.564775e-06 - 75|1.607574e-01|-1.932763e-06 - 76|1.607573e-01|-8.148685e-07 - 77|1.607554e-01|-1.187660e-05 - 78|1.607546e-01|-4.557651e-06 - 79|1.607537e-01|-5.911902e-06 + 60|1.607826e-01|-6.378947e-06 + 61|1.607808e-01|-1.145102e-05 + 62|1.607776e-01|-1.941743e-05 + 63|1.607743e-01|-2.087422e-05 + 64|1.607741e-01|-1.310249e-06 + 65|1.607738e-01|-1.682752e-06 + 66|1.607691e-01|-2.913936e-05 + 67|1.607671e-01|-1.288855e-05 + 68|1.607654e-01|-1.002448e-05 + 69|1.607641e-01|-8.209492e-06 + 70|1.607632e-01|-5.588467e-06 + 71|1.607619e-01|-8.050388e-06 + 72|1.607618e-01|-9.417493e-07 + 73|1.607598e-01|-1.210509e-05 + 74|1.607591e-01|-4.392914e-06 + 75|1.607579e-01|-7.759587e-06 + 76|1.607574e-01|-2.760280e-06 + 77|1.607556e-01|-1.146469e-05 + 78|1.607550e-01|-3.689456e-06 + 79|1.607550e-01|-4.065631e-08 It. |Loss |Delta loss -------------------------------- - 80|1.607529e-01|-4.710187e-06 - 81|1.607528e-01|-8.866080e-07 - 82|1.607522e-01|-3.620627e-06 - 83|1.607514e-01|-5.091281e-06 - 84|1.607498e-01|-9.932095e-06 - 85|1.607487e-01|-6.852804e-06 - 86|1.607478e-01|-5.373596e-06 - 87|1.607473e-01|-3.287295e-06 - 88|1.607470e-01|-1.666655e-06 - 89|1.607469e-01|-5.293790e-07 - 90|1.607466e-01|-2.051914e-06 - 91|1.607456e-01|-6.422797e-06 - 92|1.607456e-01|-1.110433e-07 - 93|1.607451e-01|-2.803849e-06 - 94|1.607451e-01|-2.608066e-07 - 95|1.607441e-01|-6.290352e-06 - 96|1.607429e-01|-7.298455e-06 - 97|1.607429e-01|-8.969905e-09 - 98|1.607427e-01|-7.923968e-07 - 99|1.607427e-01|-3.519286e-07 + 80|1.607539e-01|-6.555681e-06 + 81|1.607528e-01|-7.177470e-06 + 82|1.607527e-01|-5.306068e-07 + 83|1.607514e-01|-7.816045e-06 + 84|1.607511e-01|-2.301970e-06 + 85|1.607504e-01|-4.281072e-06 + 86|1.607503e-01|-7.821886e-07 + 87|1.607480e-01|-1.403013e-05 + 88|1.607480e-01|-1.169298e-08 + 89|1.607473e-01|-4.235982e-06 + 90|1.607470e-01|-1.717105e-06 + 91|1.607470e-01|-6.148402e-09 + 92|1.607462e-01|-5.396481e-06 + 93|1.607461e-01|-5.194954e-07 + 94|1.607450e-01|-6.525707e-06 + 95|1.607442e-01|-5.332060e-06 + 96|1.607439e-01|-1.682093e-06 + 97|1.607437e-01|-1.594796e-06 + 98|1.607435e-01|-7.923812e-07 + 99|1.607420e-01|-9.738552e-06 It. |Loss |Delta loss -------------------------------- - 100|1.607426e-01|-3.563804e-07 - 101|1.607410e-01|-1.004042e-05 - 102|1.607410e-01|-2.124801e-07 - 103|1.607398e-01|-7.556935e-06 - 104|1.607398e-01|-7.606853e-08 - 105|1.607385e-01|-8.058684e-06 - 106|1.607383e-01|-7.393061e-07 - 107|1.607381e-01|-1.504958e-06 - 108|1.607377e-01|-2.508807e-06 - 109|1.607371e-01|-4.004631e-06 - 110|1.607365e-01|-3.580156e-06 - 111|1.607364e-01|-2.563573e-07 - 112|1.607354e-01|-6.390137e-06 - 113|1.607348e-01|-4.119553e-06 - 114|1.607339e-01|-5.299475e-06 - 115|1.607335e-01|-2.316767e-06 - 116|1.607330e-01|-3.444737e-06 - 117|1.607324e-01|-3.467980e-06 - 118|1.607320e-01|-2.374632e-06 - 119|1.607319e-01|-7.978255e-07 + 100|1.607419e-01|-1.022448e-07 + 101|1.607419e-01|-4.865999e-07 + 102|1.607418e-01|-7.092012e-07 + 103|1.607408e-01|-5.861815e-06 + 104|1.607402e-01|-3.953266e-06 + 105|1.607395e-01|-3.969572e-06 + 106|1.607390e-01|-3.612075e-06 + 107|1.607377e-01|-7.683735e-06 + 108|1.607365e-01|-7.777599e-06 + 109|1.607364e-01|-2.335096e-07 + 110|1.607364e-01|-4.562036e-07 + 111|1.607360e-01|-2.089538e-06 + 112|1.607356e-01|-2.755355e-06 + 113|1.607349e-01|-4.501960e-06 + 114|1.607347e-01|-1.160544e-06 + 115|1.607346e-01|-6.289450e-07 + 116|1.607345e-01|-2.092146e-07 + 117|1.607336e-01|-5.990866e-06 + 118|1.607330e-01|-3.348498e-06 + 119|1.607328e-01|-1.256222e-06 It. |Loss |Delta loss -------------------------------- - 120|1.607312e-01|-4.221434e-06 - 121|1.607310e-01|-1.324597e-06 - 122|1.607304e-01|-3.650359e-06 - 123|1.607298e-01|-3.732712e-06 - 124|1.607295e-01|-1.994082e-06 - 125|1.607289e-01|-3.954139e-06 - 126|1.607286e-01|-1.532372e-06 - 127|1.607286e-01|-1.167223e-07 - 128|1.607283e-01|-2.157376e-06 - 129|1.607279e-01|-2.253077e-06 - 130|1.607274e-01|-3.301532e-06 - 131|1.607269e-01|-2.650754e-06 - 132|1.607264e-01|-3.595551e-06 - 133|1.607262e-01|-1.159425e-06 - 134|1.607258e-01|-2.512411e-06 - 135|1.607255e-01|-1.998792e-06 - 136|1.607251e-01|-2.486536e-06 - 137|1.607246e-01|-2.782996e-06 - 138|1.607246e-01|-2.922470e-07 - 139|1.607242e-01|-2.071131e-06 + 120|1.607320e-01|-5.418353e-06 + 121|1.607318e-01|-8.296189e-07 + 122|1.607311e-01|-4.381608e-06 + 123|1.607310e-01|-8.913901e-07 + 124|1.607309e-01|-3.808821e-07 + 125|1.607302e-01|-4.608994e-06 + 126|1.607294e-01|-5.063777e-06 + 127|1.607290e-01|-2.532835e-06 + 128|1.607285e-01|-2.870049e-06 + 129|1.607284e-01|-4.892812e-07 + 130|1.607281e-01|-1.760452e-06 + 131|1.607279e-01|-1.727139e-06 + 132|1.607275e-01|-2.220706e-06 + 133|1.607271e-01|-2.516930e-06 + 134|1.607269e-01|-1.201434e-06 + 135|1.607269e-01|-2.183459e-09 + 136|1.607262e-01|-4.223011e-06 + 137|1.607258e-01|-2.530202e-06 + 138|1.607258e-01|-1.857260e-07 + 139|1.607256e-01|-1.401957e-06 It. |Loss |Delta loss -------------------------------- - 140|1.607237e-01|-3.154193e-06 - 141|1.607235e-01|-1.194962e-06 - 142|1.607232e-01|-2.035251e-06 - 143|1.607232e-01|-6.027855e-08 - 144|1.607229e-01|-1.555696e-06 - 145|1.607228e-01|-1.081740e-06 - 146|1.607225e-01|-1.881070e-06 - 147|1.607224e-01|-4.100096e-07 - 148|1.607223e-01|-7.785200e-07 - 149|1.607222e-01|-2.094072e-07 - 150|1.607220e-01|-1.440814e-06 - 151|1.607217e-01|-1.997794e-06 - 152|1.607214e-01|-2.011022e-06 - 153|1.607212e-01|-8.808854e-07 - 154|1.607211e-01|-7.245877e-07 - 155|1.607207e-01|-2.217159e-06 - 156|1.607201e-01|-3.817891e-06 - 157|1.607200e-01|-7.409600e-07 - 158|1.607198e-01|-1.497698e-06 - 159|1.607195e-01|-1.729666e-06 + 140|1.607250e-01|-3.242751e-06 + 141|1.607247e-01|-2.308071e-06 + 142|1.607247e-01|-4.730700e-08 + 143|1.607246e-01|-4.240229e-07 + 144|1.607242e-01|-2.484810e-06 + 145|1.607238e-01|-2.539206e-06 + 146|1.607234e-01|-2.535574e-06 + 147|1.607231e-01|-1.954802e-06 + 148|1.607228e-01|-1.765447e-06 + 149|1.607228e-01|-1.620007e-08 + 150|1.607222e-01|-3.615783e-06 + 151|1.607222e-01|-8.668516e-08 + 152|1.607215e-01|-4.000673e-06 + 153|1.607213e-01|-1.774103e-06 + 154|1.607213e-01|-6.328834e-09 + 155|1.607209e-01|-2.418783e-06 + 156|1.607208e-01|-2.848492e-07 + 157|1.607207e-01|-8.836043e-07 + 158|1.607205e-01|-1.192836e-06 + 159|1.607202e-01|-1.638022e-06 It. |Loss |Delta loss -------------------------------- - 160|1.607195e-01|-2.115187e-07 - 161|1.607192e-01|-1.643727e-06 - 162|1.607192e-01|-1.712969e-07 - 163|1.607189e-01|-1.805877e-06 - 164|1.607189e-01|-1.209827e-07 - 165|1.607185e-01|-2.060002e-06 - 166|1.607182e-01|-1.961341e-06 - 167|1.607181e-01|-1.020366e-06 - 168|1.607179e-01|-9.760982e-07 - 169|1.607178e-01|-7.219236e-07 - 170|1.607175e-01|-1.837718e-06 - 171|1.607174e-01|-3.337578e-07 - 172|1.607173e-01|-5.298564e-07 - 173|1.607173e-01|-6.864278e-08 - 174|1.607173e-01|-2.008419e-07 - 175|1.607171e-01|-1.375630e-06 - 176|1.607168e-01|-1.911257e-06 - 177|1.607167e-01|-2.709815e-07 - 178|1.607167e-01|-1.390953e-07 - 179|1.607165e-01|-1.199675e-06 - It. |Loss |Delta loss - -------------------------------- - 180|1.607165e-01|-1.457259e-07 - 181|1.607163e-01|-1.049154e-06 - 182|1.607163e-01|-2.753577e-09 - 183|1.607163e-01|-6.972814e-09 - 184|1.607161e-01|-1.552100e-06 - 185|1.607159e-01|-1.068596e-06 - 186|1.607157e-01|-1.247724e-06 - 187|1.607155e-01|-1.158164e-06 - 188|1.607155e-01|-2.616199e-07 - 189|1.607154e-01|-3.595874e-07 - 190|1.607154e-01|-5.334527e-08 - 191|1.607153e-01|-3.452744e-07 - 192|1.607153e-01|-1.239593e-07 - 193|1.607152e-01|-8.184984e-07 - 194|1.607150e-01|-1.316308e-06 - 195|1.607150e-01|-7.100882e-09 - 196|1.607148e-01|-1.393958e-06 - 197|1.607146e-01|-1.242735e-06 - 198|1.607144e-01|-1.123993e-06 - 199|1.607143e-01|-3.512071e-07 - It. |Loss |Delta loss - -------------------------------- - 200|1.607143e-01|-2.151971e-10 + 160|1.607202e-01|-3.670914e-08 + 161|1.607197e-01|-3.153709e-06 + 162|1.607197e-01|-2.419565e-09 + 163|1.607194e-01|-2.136882e-06 + 164|1.607194e-01|-1.173754e-09 + 165|1.607192e-01|-8.169238e-07 + 166|1.607191e-01|-9.218755e-07 + 167|1.607189e-01|-9.459255e-07 + 168|1.607187e-01|-1.294835e-06 + 169|1.607186e-01|-5.797668e-07 + 170|1.607186e-01|-4.706272e-08 + 171|1.607183e-01|-1.753383e-06 + 172|1.607183e-01|-1.681573e-07 + 173|1.607183e-01|-2.563971e-10 Solve EMD with Frobenius norm + entropic regularization @@ -667,7 +636,7 @@ Solve EMD with Frobenius norm + entropic regularization 4|1.609284e-01|-1.111407e-12 -**Total running time of the script:** ( 0 minutes 1.809 seconds) +**Total running time of the script:** ( 0 minutes 2.800 seconds) @@ -686,4 +655,4 @@ Solve EMD with Frobenius norm + entropic regularization .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_otda_classes.rst b/docs/source/auto_examples/plot_otda_classes.rst index f19a99f..a5ab285 100644 --- a/docs/source/auto_examples/plot_otda_classes.rst +++ b/docs/source/auto_examples/plot_otda_classes.rst @@ -94,29 +94,29 @@ Instantiate the different transport algorithms and fit them It. |Loss |Delta loss -------------------------------- - 0|9.552437e+00|0.000000e+00 - 1|1.921833e+00|-3.970483e+00 - 2|1.671022e+00|-1.500942e-01 - 3|1.615147e+00|-3.459458e-02 - 4|1.594289e+00|-1.308252e-02 - 5|1.587287e+00|-4.411254e-03 - 6|1.581665e+00|-3.554702e-03 - 7|1.577022e+00|-2.943809e-03 - 8|1.573870e+00|-2.002870e-03 - 9|1.571645e+00|-1.415696e-03 - 10|1.569342e+00|-1.467590e-03 - 11|1.567863e+00|-9.432233e-04 - 12|1.566558e+00|-8.329769e-04 - 13|1.565414e+00|-7.311320e-04 - 14|1.564425e+00|-6.319985e-04 - 15|1.563955e+00|-3.007604e-04 - 16|1.563658e+00|-1.894627e-04 - 17|1.562886e+00|-4.941143e-04 - 18|1.562578e+00|-1.974031e-04 - 19|1.562445e+00|-8.468825e-05 + 0|1.003747e+01|0.000000e+00 + 1|1.953263e+00|-4.138821e+00 + 2|1.744456e+00|-1.196969e-01 + 3|1.689268e+00|-3.267022e-02 + 4|1.666355e+00|-1.374998e-02 + 5|1.656125e+00|-6.177356e-03 + 6|1.651753e+00|-2.646960e-03 + 7|1.647261e+00|-2.726957e-03 + 8|1.642274e+00|-3.036672e-03 + 9|1.639926e+00|-1.431818e-03 + 10|1.638750e+00|-7.173837e-04 + 11|1.637558e+00|-7.281753e-04 + 12|1.636248e+00|-8.002067e-04 + 13|1.634555e+00|-1.036074e-03 + 14|1.633547e+00|-6.166646e-04 + 15|1.633531e+00|-1.022614e-05 + 16|1.632957e+00|-3.510986e-04 + 17|1.632853e+00|-6.380944e-05 + 18|1.632704e+00|-9.122988e-05 + 19|1.632237e+00|-2.861276e-04 It. |Loss |Delta loss -------------------------------- - 20|1.562007e+00|-2.805136e-04 + 20|1.632174e+00|-3.896483e-05 Fig 1 : plots source and target samples @@ -236,7 +236,7 @@ Fig 2 : plot optimal couplings and transported samples -**Total running time of the script:** ( 0 minutes 1.596 seconds) +**Total running time of the script:** ( 0 minutes 2.308 seconds) @@ -255,4 +255,4 @@ Fig 2 : plot optimal couplings and transported samples .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_otda_color_images.rst b/docs/source/auto_examples/plot_otda_color_images.rst index 4772bed..9c31ba7 100644 --- a/docs/source/auto_examples/plot_otda_color_images.rst +++ b/docs/source/auto_examples/plot_otda_color_images.rst @@ -235,7 +235,7 @@ Plot new images -**Total running time of the script:** ( 2 minutes 24.561 seconds) +**Total running time of the script:** ( 3 minutes 16.469 seconds) @@ -254,4 +254,4 @@ Plot new images .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_otda_d2.rst b/docs/source/auto_examples/plot_otda_d2.rst index 2b716e1..1bbe6d9 100644 --- a/docs/source/auto_examples/plot_otda_d2.rst +++ b/docs/source/auto_examples/plot_otda_d2.rst @@ -242,7 +242,7 @@ Fig 3 : plot transported samples -**Total running time of the script:** ( 0 minutes 32.084 seconds) +**Total running time of the script:** ( 0 minutes 47.000 seconds) @@ -261,4 +261,4 @@ Fig 3 : plot transported samples .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_otda_mapping.rst b/docs/source/auto_examples/plot_otda_mapping.rst index 6c1c780..1e3a709 100644 --- a/docs/source/auto_examples/plot_otda_mapping.rst +++ b/docs/source/auto_examples/plot_otda_mapping.rst @@ -136,24 +136,26 @@ Instantiate the different transport algorithms and fit them It. |Loss |Delta loss -------------------------------- - 0|4.307233e+03|0.000000e+00 - 1|4.296694e+03|-2.446759e-03 - 2|4.296419e+03|-6.417421e-05 - 3|4.296328e+03|-2.110209e-05 - 4|4.296305e+03|-5.298603e-06 + 0|4.231423e+03|0.000000e+00 + 1|4.217955e+03|-3.182835e-03 + 2|4.217580e+03|-8.885864e-05 + 3|4.217451e+03|-3.043162e-05 + 4|4.217368e+03|-1.978325e-05 + 5|4.217312e+03|-1.338471e-05 + 6|4.217307e+03|-1.000290e-06 It. |Loss |Delta loss -------------------------------- - 0|4.325624e+02|0.000000e+00 - 1|4.281958e+02|-1.009489e-02 - 2|4.279370e+02|-6.042202e-04 - 3|4.278109e+02|-2.947651e-04 - 4|4.277212e+02|-2.096651e-04 - 5|4.276589e+02|-1.456221e-04 - 6|4.276141e+02|-1.048476e-04 - 7|4.275803e+02|-7.906213e-05 - 8|4.275531e+02|-6.360573e-05 - 9|4.275314e+02|-5.076642e-05 - 10|4.275129e+02|-4.325858e-05 + 0|4.257004e+02|0.000000e+00 + 1|4.208978e+02|-1.128168e-02 + 2|4.205168e+02|-9.052112e-04 + 3|4.203566e+02|-3.810681e-04 + 4|4.202570e+02|-2.369884e-04 + 5|4.201844e+02|-1.726132e-04 + 6|4.201341e+02|-1.196461e-04 + 7|4.200941e+02|-9.525441e-05 + 8|4.200630e+02|-7.405552e-05 + 9|4.200377e+02|-6.031884e-05 + 10|4.200168e+02|-4.968324e-05 Plot transported samples @@ -206,7 +208,7 @@ Plot transported samples -**Total running time of the script:** ( 0 minutes 0.747 seconds) +**Total running time of the script:** ( 0 minutes 0.970 seconds) @@ -225,4 +227,4 @@ Plot transported samples .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_otda_mapping_colors_images.rst b/docs/source/auto_examples/plot_otda_mapping_colors_images.rst index 86b1312..8394fb0 100644 --- a/docs/source/auto_examples/plot_otda_mapping_colors_images.rst +++ b/docs/source/auto_examples/plot_otda_mapping_colors_images.rst @@ -132,39 +132,39 @@ Domain adaptation for pixel distribution transfer It. |Loss |Delta loss -------------------------------- - 0|3.680512e+02|0.000000e+00 - 1|3.592454e+02|-2.392562e-02 - 2|3.590671e+02|-4.960473e-04 - 3|3.589736e+02|-2.604894e-04 - 4|3.589161e+02|-1.602816e-04 - 5|3.588766e+02|-1.099971e-04 - 6|3.588476e+02|-8.084400e-05 - 7|3.588256e+02|-6.131161e-05 - 8|3.588083e+02|-4.807549e-05 - 9|3.587943e+02|-3.899414e-05 - 10|3.587827e+02|-3.245280e-05 - 11|3.587729e+02|-2.721256e-05 - 12|3.587646e+02|-2.316249e-05 - 13|3.587574e+02|-2.000192e-05 - 14|3.587512e+02|-1.748898e-05 - 15|3.587457e+02|-1.535131e-05 - 16|3.587408e+02|-1.366515e-05 - 17|3.587364e+02|-1.210563e-05 - 18|3.587325e+02|-1.097138e-05 - 19|3.587310e+02|-4.099596e-06 + 0|3.680518e+02|0.000000e+00 + 1|3.592439e+02|-2.393116e-02 + 2|3.590632e+02|-5.030248e-04 + 3|3.589698e+02|-2.601358e-04 + 4|3.589118e+02|-1.614977e-04 + 5|3.588724e+02|-1.097608e-04 + 6|3.588436e+02|-8.035205e-05 + 7|3.588215e+02|-6.141923e-05 + 8|3.588042e+02|-4.832627e-05 + 9|3.587902e+02|-3.909574e-05 + 10|3.587786e+02|-3.225418e-05 + 11|3.587688e+02|-2.712592e-05 + 12|3.587605e+02|-2.314041e-05 + 13|3.587534e+02|-1.991287e-05 + 14|3.587471e+02|-1.744348e-05 + 15|3.587416e+02|-1.544523e-05 + 16|3.587367e+02|-1.364654e-05 + 17|3.587323e+02|-1.230435e-05 + 18|3.587284e+02|-1.093370e-05 + 19|3.587276e+02|-2.052728e-06 It. |Loss |Delta loss -------------------------------- - 0|3.784805e+02|0.000000e+00 - 1|3.646476e+02|-3.654847e-02 - 2|3.642970e+02|-9.615381e-04 - 3|3.641622e+02|-3.699897e-04 - 4|3.640886e+02|-2.021154e-04 - 5|3.640419e+02|-1.280913e-04 - 6|3.640096e+02|-8.898145e-05 - 7|3.639858e+02|-6.514301e-05 - 8|3.639677e+02|-4.977195e-05 - 9|3.639534e+02|-3.936050e-05 - 10|3.639417e+02|-3.205223e-05 + 0|3.784758e+02|0.000000e+00 + 1|3.646352e+02|-3.656911e-02 + 2|3.642861e+02|-9.574714e-04 + 3|3.641523e+02|-3.672061e-04 + 4|3.640788e+02|-2.020990e-04 + 5|3.640321e+02|-1.282701e-04 + 6|3.640002e+02|-8.751240e-05 + 7|3.639765e+02|-6.521203e-05 + 8|3.639582e+02|-5.007767e-05 + 9|3.639439e+02|-3.938917e-05 + 10|3.639323e+02|-3.187865e-05 Plot original images @@ -283,7 +283,7 @@ Plot transformed images -**Total running time of the script:** ( 2 minutes 5.213 seconds) +**Total running time of the script:** ( 2 minutes 52.212 seconds) @@ -302,4 +302,4 @@ Plot transformed images .. rst-class:: sphx-glr-signature - `Generated by Sphinx-Gallery `_ + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/auto_examples/plot_otda_semi_supervised.ipynb b/docs/source/auto_examples/plot_otda_semi_supervised.ipynb new file mode 100644 index 0000000..783bf84 --- /dev/null +++ b/docs/source/auto_examples/plot_otda_semi_supervised.ipynb @@ -0,0 +1,144 @@ +{ + "nbformat_minor": 0, + "nbformat": 4, + "cells": [ + { + "execution_count": null, + "cell_type": "code", + "source": [ + "%matplotlib inline" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "\n# OTDA unsupervised vs semi-supervised setting\n\n\nThis example introduces a semi supervised domain adaptation in a 2D setting.\nIt explicits the problem of semi supervised domain adaptation and introduces\nsome optimal transport approaches to solve it.\n\nQuantities such as optimal couplings, greater coupling coefficients and\ntransported samples are represented in order to give a visual understanding\nof what the transport methods are doing.\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "# Authors: Remi Flamary \n# Stanislas Chambon \n#\n# License: MIT License\n\nimport matplotlib.pylab as pl\nimport ot" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Generate data\n-------------\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "n_samples_source = 150\nn_samples_target = 150\n\nXs, ys = ot.datasets.get_data_classif('3gauss', n_samples_source)\nXt, yt = ot.datasets.get_data_classif('3gauss2', n_samples_target)" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Transport source samples onto target samples\n--------------------------------------------\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "# unsupervised domain adaptation\not_sinkhorn_un = ot.da.SinkhornTransport(reg_e=1e-1)\not_sinkhorn_un.fit(Xs=Xs, Xt=Xt)\ntransp_Xs_sinkhorn_un = ot_sinkhorn_un.transform(Xs=Xs)\n\n# semi-supervised domain adaptation\not_sinkhorn_semi = ot.da.SinkhornTransport(reg_e=1e-1)\not_sinkhorn_semi.fit(Xs=Xs, Xt=Xt, ys=ys, yt=yt)\ntransp_Xs_sinkhorn_semi = ot_sinkhorn_semi.transform(Xs=Xs)\n\n# semi supervised DA uses available labaled target samples to modify the cost\n# matrix involved in the OT problem. The cost of transporting a source sample\n# of class A onto a target sample of class B != A is set to infinite, or a\n# very large value\n\n# note that in the present case we consider that all the target samples are\n# labeled. For daily applications, some target sample might not have labels,\n# in this case the element of yt corresponding to these samples should be\n# filled with -1.\n\n# Warning: we recall that -1 cannot be used as a class label" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Fig 1 : plots source and target samples + matrix of pairwise distance\n---------------------------------------------------------------------\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "pl.figure(1, figsize=(10, 10))\npl.subplot(2, 2, 1)\npl.scatter(Xs[:, 0], Xs[:, 1], c=ys, marker='+', label='Source samples')\npl.xticks([])\npl.yticks([])\npl.legend(loc=0)\npl.title('Source samples')\n\npl.subplot(2, 2, 2)\npl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', label='Target samples')\npl.xticks([])\npl.yticks([])\npl.legend(loc=0)\npl.title('Target samples')\n\npl.subplot(2, 2, 3)\npl.imshow(ot_sinkhorn_un.cost_, interpolation='nearest')\npl.xticks([])\npl.yticks([])\npl.title('Cost matrix - unsupervised DA')\n\npl.subplot(2, 2, 4)\npl.imshow(ot_sinkhorn_semi.cost_, interpolation='nearest')\npl.xticks([])\npl.yticks([])\npl.title('Cost matrix - semisupervised DA')\n\npl.tight_layout()\n\n# the optimal coupling in the semi-supervised DA case will exhibit \" shape\n# similar\" to the cost matrix, (block diagonal matrix)" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Fig 2 : plots optimal couplings for the different methods\n---------------------------------------------------------\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "pl.figure(2, figsize=(8, 4))\n\npl.subplot(1, 2, 1)\npl.imshow(ot_sinkhorn_un.coupling_, interpolation='nearest')\npl.xticks([])\npl.yticks([])\npl.title('Optimal coupling\\nUnsupervised DA')\n\npl.subplot(1, 2, 2)\npl.imshow(ot_sinkhorn_semi.coupling_, interpolation='nearest')\npl.xticks([])\npl.yticks([])\npl.title('Optimal coupling\\nSemi-supervised DA')\n\npl.tight_layout()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + }, + { + "source": [ + "Fig 3 : plot transported samples\n--------------------------------\n\n" + ], + "cell_type": "markdown", + "metadata": {} + }, + { + "execution_count": null, + "cell_type": "code", + "source": [ + "# display transported samples\npl.figure(4, figsize=(8, 4))\npl.subplot(1, 2, 1)\npl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o',\n label='Target samples', alpha=0.5)\npl.scatter(transp_Xs_sinkhorn_un[:, 0], transp_Xs_sinkhorn_un[:, 1], c=ys,\n marker='+', label='Transp samples', s=30)\npl.title('Transported samples\\nEmdTransport')\npl.legend(loc=0)\npl.xticks([])\npl.yticks([])\n\npl.subplot(1, 2, 2)\npl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o',\n label='Target samples', alpha=0.5)\npl.scatter(transp_Xs_sinkhorn_semi[:, 0], transp_Xs_sinkhorn_semi[:, 1], c=ys,\n marker='+', label='Transp samples', s=30)\npl.title('Transported samples\\nSinkhornTransport')\npl.xticks([])\npl.yticks([])\n\npl.tight_layout()\npl.show()" + ], + "outputs": [], + "metadata": { + "collapsed": false + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "name": "python2", + "language": "python" + }, + "language_info": { + "mimetype": "text/x-python", + "nbconvert_exporter": "python", + "name": "python", + "file_extension": ".py", + "version": "2.7.12", + "pygments_lexer": "ipython2", + "codemirror_mode": { + "version": 2, + "name": "ipython" + } + } + } +} \ No newline at end of file diff --git a/docs/source/auto_examples/plot_otda_semi_supervised.py b/docs/source/auto_examples/plot_otda_semi_supervised.py new file mode 100644 index 0000000..7963aef --- /dev/null +++ b/docs/source/auto_examples/plot_otda_semi_supervised.py @@ -0,0 +1,148 @@ +# -*- coding: utf-8 -*- +""" +============================================ +OTDA unsupervised vs semi-supervised setting +============================================ + +This example introduces a semi supervised domain adaptation in a 2D setting. +It explicits the problem of semi supervised domain adaptation and introduces +some optimal transport approaches to solve it. + +Quantities such as optimal couplings, greater coupling coefficients and +transported samples are represented in order to give a visual understanding +of what the transport methods are doing. +""" + +# Authors: Remi Flamary +# Stanislas Chambon +# +# License: MIT License + +import matplotlib.pylab as pl +import ot + + +############################################################################## +# Generate data +# ------------- + +n_samples_source = 150 +n_samples_target = 150 + +Xs, ys = ot.datasets.get_data_classif('3gauss', n_samples_source) +Xt, yt = ot.datasets.get_data_classif('3gauss2', n_samples_target) + + +############################################################################## +# Transport source samples onto target samples +# -------------------------------------------- + + +# unsupervised domain adaptation +ot_sinkhorn_un = ot.da.SinkhornTransport(reg_e=1e-1) +ot_sinkhorn_un.fit(Xs=Xs, Xt=Xt) +transp_Xs_sinkhorn_un = ot_sinkhorn_un.transform(Xs=Xs) + +# semi-supervised domain adaptation +ot_sinkhorn_semi = ot.da.SinkhornTransport(reg_e=1e-1) +ot_sinkhorn_semi.fit(Xs=Xs, Xt=Xt, ys=ys, yt=yt) +transp_Xs_sinkhorn_semi = ot_sinkhorn_semi.transform(Xs=Xs) + +# semi supervised DA uses available labaled target samples to modify the cost +# matrix involved in the OT problem. The cost of transporting a source sample +# of class A onto a target sample of class B != A is set to infinite, or a +# very large value + +# note that in the present case we consider that all the target samples are +# labeled. For daily applications, some target sample might not have labels, +# in this case the element of yt corresponding to these samples should be +# filled with -1. + +# Warning: we recall that -1 cannot be used as a class label + + +############################################################################## +# Fig 1 : plots source and target samples + matrix of pairwise distance +# --------------------------------------------------------------------- + +pl.figure(1, figsize=(10, 10)) +pl.subplot(2, 2, 1) +pl.scatter(Xs[:, 0], Xs[:, 1], c=ys, marker='+', label='Source samples') +pl.xticks([]) +pl.yticks([]) +pl.legend(loc=0) +pl.title('Source samples') + +pl.subplot(2, 2, 2) +pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', label='Target samples') +pl.xticks([]) +pl.yticks([]) +pl.legend(loc=0) +pl.title('Target samples') + +pl.subplot(2, 2, 3) +pl.imshow(ot_sinkhorn_un.cost_, interpolation='nearest') +pl.xticks([]) +pl.yticks([]) +pl.title('Cost matrix - unsupervised DA') + +pl.subplot(2, 2, 4) +pl.imshow(ot_sinkhorn_semi.cost_, interpolation='nearest') +pl.xticks([]) +pl.yticks([]) +pl.title('Cost matrix - semisupervised DA') + +pl.tight_layout() + +# the optimal coupling in the semi-supervised DA case will exhibit " shape +# similar" to the cost matrix, (block diagonal matrix) + + +############################################################################## +# Fig 2 : plots optimal couplings for the different methods +# --------------------------------------------------------- + +pl.figure(2, figsize=(8, 4)) + +pl.subplot(1, 2, 1) +pl.imshow(ot_sinkhorn_un.coupling_, interpolation='nearest') +pl.xticks([]) +pl.yticks([]) +pl.title('Optimal coupling\nUnsupervised DA') + +pl.subplot(1, 2, 2) +pl.imshow(ot_sinkhorn_semi.coupling_, interpolation='nearest') +pl.xticks([]) +pl.yticks([]) +pl.title('Optimal coupling\nSemi-supervised DA') + +pl.tight_layout() + + +############################################################################## +# Fig 3 : plot transported samples +# -------------------------------- + +# display transported samples +pl.figure(4, figsize=(8, 4)) +pl.subplot(1, 2, 1) +pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', + label='Target samples', alpha=0.5) +pl.scatter(transp_Xs_sinkhorn_un[:, 0], transp_Xs_sinkhorn_un[:, 1], c=ys, + marker='+', label='Transp samples', s=30) +pl.title('Transported samples\nEmdTransport') +pl.legend(loc=0) +pl.xticks([]) +pl.yticks([]) + +pl.subplot(1, 2, 2) +pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', + label='Target samples', alpha=0.5) +pl.scatter(transp_Xs_sinkhorn_semi[:, 0], transp_Xs_sinkhorn_semi[:, 1], c=ys, + marker='+', label='Transp samples', s=30) +pl.title('Transported samples\nSinkhornTransport') +pl.xticks([]) +pl.yticks([]) + +pl.tight_layout() +pl.show() diff --git a/docs/source/auto_examples/plot_otda_semi_supervised.rst b/docs/source/auto_examples/plot_otda_semi_supervised.rst new file mode 100644 index 0000000..dc05ed0 --- /dev/null +++ b/docs/source/auto_examples/plot_otda_semi_supervised.rst @@ -0,0 +1,240 @@ + + +.. _sphx_glr_auto_examples_plot_otda_semi_supervised.py: + + +============================================ +OTDA unsupervised vs semi-supervised setting +============================================ + +This example introduces a semi supervised domain adaptation in a 2D setting. +It explicits the problem of semi supervised domain adaptation and introduces +some optimal transport approaches to solve it. + +Quantities such as optimal couplings, greater coupling coefficients and +transported samples are represented in order to give a visual understanding +of what the transport methods are doing. + + + +.. code-block:: python + + + # Authors: Remi Flamary + # Stanislas Chambon + # + # License: MIT License + + import matplotlib.pylab as pl + import ot + + + + + + + + +Generate data +------------- + + + +.. code-block:: python + + + n_samples_source = 150 + n_samples_target = 150 + + Xs, ys = ot.datasets.get_data_classif('3gauss', n_samples_source) + Xt, yt = ot.datasets.get_data_classif('3gauss2', n_samples_target) + + + + + + + + +Transport source samples onto target samples +-------------------------------------------- + + + +.. code-block:: python + + + + # unsupervised domain adaptation + ot_sinkhorn_un = ot.da.SinkhornTransport(reg_e=1e-1) + ot_sinkhorn_un.fit(Xs=Xs, Xt=Xt) + transp_Xs_sinkhorn_un = ot_sinkhorn_un.transform(Xs=Xs) + + # semi-supervised domain adaptation + ot_sinkhorn_semi = ot.da.SinkhornTransport(reg_e=1e-1) + ot_sinkhorn_semi.fit(Xs=Xs, Xt=Xt, ys=ys, yt=yt) + transp_Xs_sinkhorn_semi = ot_sinkhorn_semi.transform(Xs=Xs) + + # semi supervised DA uses available labaled target samples to modify the cost + # matrix involved in the OT problem. The cost of transporting a source sample + # of class A onto a target sample of class B != A is set to infinite, or a + # very large value + + # note that in the present case we consider that all the target samples are + # labeled. For daily applications, some target sample might not have labels, + # in this case the element of yt corresponding to these samples should be + # filled with -1. + + # Warning: we recall that -1 cannot be used as a class label + + + + + + + + +Fig 1 : plots source and target samples + matrix of pairwise distance +--------------------------------------------------------------------- + + + +.. code-block:: python + + + pl.figure(1, figsize=(10, 10)) + pl.subplot(2, 2, 1) + pl.scatter(Xs[:, 0], Xs[:, 1], c=ys, marker='+', label='Source samples') + pl.xticks([]) + pl.yticks([]) + pl.legend(loc=0) + pl.title('Source samples') + + pl.subplot(2, 2, 2) + pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', label='Target samples') + pl.xticks([]) + pl.yticks([]) + pl.legend(loc=0) + pl.title('Target samples') + + pl.subplot(2, 2, 3) + pl.imshow(ot_sinkhorn_un.cost_, interpolation='nearest') + pl.xticks([]) + pl.yticks([]) + pl.title('Cost matrix - unsupervised DA') + + pl.subplot(2, 2, 4) + pl.imshow(ot_sinkhorn_semi.cost_, interpolation='nearest') + pl.xticks([]) + pl.yticks([]) + pl.title('Cost matrix - semisupervised DA') + + pl.tight_layout() + + # the optimal coupling in the semi-supervised DA case will exhibit " shape + # similar" to the cost matrix, (block diagonal matrix) + + + + + +.. image:: /auto_examples/images/sphx_glr_plot_otda_semi_supervised_001.png + :align: center + + + + +Fig 2 : plots optimal couplings for the different methods +--------------------------------------------------------- + + + +.. code-block:: python + + + pl.figure(2, figsize=(8, 4)) + + pl.subplot(1, 2, 1) + pl.imshow(ot_sinkhorn_un.coupling_, interpolation='nearest') + pl.xticks([]) + pl.yticks([]) + pl.title('Optimal coupling\nUnsupervised DA') + + pl.subplot(1, 2, 2) + pl.imshow(ot_sinkhorn_semi.coupling_, interpolation='nearest') + pl.xticks([]) + pl.yticks([]) + pl.title('Optimal coupling\nSemi-supervised DA') + + pl.tight_layout() + + + + + +.. image:: /auto_examples/images/sphx_glr_plot_otda_semi_supervised_003.png + :align: center + + + + +Fig 3 : plot transported samples +-------------------------------- + + + +.. code-block:: python + + + # display transported samples + pl.figure(4, figsize=(8, 4)) + pl.subplot(1, 2, 1) + pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', + label='Target samples', alpha=0.5) + pl.scatter(transp_Xs_sinkhorn_un[:, 0], transp_Xs_sinkhorn_un[:, 1], c=ys, + marker='+', label='Transp samples', s=30) + pl.title('Transported samples\nEmdTransport') + pl.legend(loc=0) + pl.xticks([]) + pl.yticks([]) + + pl.subplot(1, 2, 2) + pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', + label='Target samples', alpha=0.5) + pl.scatter(transp_Xs_sinkhorn_semi[:, 0], transp_Xs_sinkhorn_semi[:, 1], c=ys, + marker='+', label='Transp samples', s=30) + pl.title('Transported samples\nSinkhornTransport') + pl.xticks([]) + pl.yticks([]) + + pl.tight_layout() + pl.show() + + + +.. image:: /auto_examples/images/sphx_glr_plot_otda_semi_supervised_006.png + :align: center + + + + +**Total running time of the script:** ( 0 minutes 0.714 seconds) + + + +.. container:: sphx-glr-footer + + + .. container:: sphx-glr-download + + :download:`Download Python source code: plot_otda_semi_supervised.py ` + + + + .. container:: sphx-glr-download + + :download:`Download Jupyter notebook: plot_otda_semi_supervised.ipynb ` + +.. rst-class:: sphx-glr-signature + + `Generated by Sphinx-Gallery `_ diff --git a/docs/source/conf.py b/docs/source/conf.py index 7bf392c..4105d87 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -33,7 +33,7 @@ class Mock(MagicMock): return MagicMock() MOCK_MODULES = ['ot.lp.emd_wrap','autograd','pymanopt','cudamat','autograd.numpy','pymanopt.manifolds','pymanopt.solvers'] # 'autograd.numpy','pymanopt.manifolds','pymanopt.solvers', -#sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES) +sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES) # !!!! # If extensions (or modules to document with autodoc) are in another directory, @@ -62,7 +62,7 @@ extensions = [ 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', 'sphinx.ext.napoleon', - 'sphinx_gallery.gen_gallery', + #'sphinx_gallery.gen_gallery', ] # Add any paths that contain templates here, relative to this directory. diff --git a/examples/plot_gromov.py b/examples/plot_gromov.py index 5132024..d3f724c 100644 --- a/examples/plot_gromov.py +++ b/examples/plot_gromov.py @@ -20,13 +20,14 @@ from mpl_toolkits.mplot3d import Axes3D # noqa import ot -""" -Sample two Gaussian distributions (2D and 3D) -============================================= -The Gromov-Wasserstein distance allows to compute distances with samples that -do not belong to the same metric space. For demonstration purpose, we sample -two Gaussian distributions in 2- and 3-dimensional spaces. -""" +############################################################################## +# Sample two Gaussian distributions (2D and 3D) +# --------------------------------------------- +# +# The Gromov-Wasserstein distance allows to compute distances with samples that +# do not belong to the same metric space. For demonstration purpose, we sample +# two Gaussian distributions in 2- and 3-dimensional spaces. + n_samples = 30 # nb samples @@ -42,10 +43,11 @@ P = sp.linalg.sqrtm(cov_t) xt = np.random.randn(n_samples, 3).dot(P) + mu_t -""" -Plotting the distributions -========================== -""" +############################################################################## +# Plotting the distributions +# -------------------------- + + fig = pl.figure() ax1 = fig.add_subplot(121) ax1.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples') @@ -54,10 +56,10 @@ ax2.scatter(xt[:, 0], xt[:, 1], xt[:, 2], color='r') pl.show() -""" -Compute distance kernels, normalize them and then display -========================================================= -""" +############################################################################## +# Compute distance kernels, normalize them and then display +# --------------------------------------------------------- + C1 = sp.spatial.distance.cdist(xs, xs) C2 = sp.spatial.distance.cdist(xt, xt) @@ -72,10 +74,10 @@ pl.subplot(122) pl.imshow(C2) pl.show() -""" -Compute Gromov-Wasserstein plans and distance -============================================= -""" +############################################################################## +# Compute Gromov-Wasserstein plans and distance +# --------------------------------------------- + p = ot.unif(n_samples) q = ot.unif(n_samples) diff --git a/examples/plot_gromov_barycenter.py b/examples/plot_gromov_barycenter.py index 93533c0..180b0cf 100755 --- a/examples/plot_gromov_barycenter.py +++ b/examples/plot_gromov_barycenter.py @@ -24,12 +24,12 @@ from sklearn.decomposition import PCA import ot -""" -Smacof MDS -========== -This function allows to find an embedding of points given a dissimilarity matrix -that will be given by the output of the algorithm -""" +############################################################################## +# Smacof MDS +# ---------- +# +# This function allows to find an embedding of points given a dissimilarity matrix +# that will be given by the output of the algorithm def smacof_mds(C, dim, max_iter=3000, eps=1e-9): @@ -78,11 +78,11 @@ def smacof_mds(C, dim, max_iter=3000, eps=1e-9): return npos -""" -Data preparation -================ -The four distributions are constructed from 4 simple images -""" +############################################################################## +# Data preparation +# ---------------- +# +# The four distributions are constructed from 4 simple images def im2mat(I): @@ -110,12 +110,11 @@ for nb in range(4): xs = np.array([np.array(xs[0]), np.array(xs[1]), np.array(xs[2]), np.array(xs[3])]) +############################################################################## +# Barycenter computation +# ---------------------- + -""" -Barycenter computation -====================== -The four distributions are constructed from 4 simple images -""" ns = [len(xs[s]) for s in range(S)] n_samples = 30 @@ -157,12 +156,13 @@ for i in range(2): ], p, lambdast[i], 'square_loss', 5e-4, max_iter=100, tol=1e-3) -""" -Visualization -============= -""" -"""The PCA helps in getting consistency between the rotations""" +############################################################################## +# Visualization +# ------------- +# +# The PCA helps in getting consistency between the rotations + clf = PCA(n_components=2) npos = [0, 0, 0, 0] diff --git a/examples/plot_otda_semi_supervised.py b/examples/plot_otda_semi_supervised.py new file mode 100644 index 0000000..7963aef --- /dev/null +++ b/examples/plot_otda_semi_supervised.py @@ -0,0 +1,148 @@ +# -*- coding: utf-8 -*- +""" +============================================ +OTDA unsupervised vs semi-supervised setting +============================================ + +This example introduces a semi supervised domain adaptation in a 2D setting. +It explicits the problem of semi supervised domain adaptation and introduces +some optimal transport approaches to solve it. + +Quantities such as optimal couplings, greater coupling coefficients and +transported samples are represented in order to give a visual understanding +of what the transport methods are doing. +""" + +# Authors: Remi Flamary +# Stanislas Chambon +# +# License: MIT License + +import matplotlib.pylab as pl +import ot + + +############################################################################## +# Generate data +# ------------- + +n_samples_source = 150 +n_samples_target = 150 + +Xs, ys = ot.datasets.get_data_classif('3gauss', n_samples_source) +Xt, yt = ot.datasets.get_data_classif('3gauss2', n_samples_target) + + +############################################################################## +# Transport source samples onto target samples +# -------------------------------------------- + + +# unsupervised domain adaptation +ot_sinkhorn_un = ot.da.SinkhornTransport(reg_e=1e-1) +ot_sinkhorn_un.fit(Xs=Xs, Xt=Xt) +transp_Xs_sinkhorn_un = ot_sinkhorn_un.transform(Xs=Xs) + +# semi-supervised domain adaptation +ot_sinkhorn_semi = ot.da.SinkhornTransport(reg_e=1e-1) +ot_sinkhorn_semi.fit(Xs=Xs, Xt=Xt, ys=ys, yt=yt) +transp_Xs_sinkhorn_semi = ot_sinkhorn_semi.transform(Xs=Xs) + +# semi supervised DA uses available labaled target samples to modify the cost +# matrix involved in the OT problem. The cost of transporting a source sample +# of class A onto a target sample of class B != A is set to infinite, or a +# very large value + +# note that in the present case we consider that all the target samples are +# labeled. For daily applications, some target sample might not have labels, +# in this case the element of yt corresponding to these samples should be +# filled with -1. + +# Warning: we recall that -1 cannot be used as a class label + + +############################################################################## +# Fig 1 : plots source and target samples + matrix of pairwise distance +# --------------------------------------------------------------------- + +pl.figure(1, figsize=(10, 10)) +pl.subplot(2, 2, 1) +pl.scatter(Xs[:, 0], Xs[:, 1], c=ys, marker='+', label='Source samples') +pl.xticks([]) +pl.yticks([]) +pl.legend(loc=0) +pl.title('Source samples') + +pl.subplot(2, 2, 2) +pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', label='Target samples') +pl.xticks([]) +pl.yticks([]) +pl.legend(loc=0) +pl.title('Target samples') + +pl.subplot(2, 2, 3) +pl.imshow(ot_sinkhorn_un.cost_, interpolation='nearest') +pl.xticks([]) +pl.yticks([]) +pl.title('Cost matrix - unsupervised DA') + +pl.subplot(2, 2, 4) +pl.imshow(ot_sinkhorn_semi.cost_, interpolation='nearest') +pl.xticks([]) +pl.yticks([]) +pl.title('Cost matrix - semisupervised DA') + +pl.tight_layout() + +# the optimal coupling in the semi-supervised DA case will exhibit " shape +# similar" to the cost matrix, (block diagonal matrix) + + +############################################################################## +# Fig 2 : plots optimal couplings for the different methods +# --------------------------------------------------------- + +pl.figure(2, figsize=(8, 4)) + +pl.subplot(1, 2, 1) +pl.imshow(ot_sinkhorn_un.coupling_, interpolation='nearest') +pl.xticks([]) +pl.yticks([]) +pl.title('Optimal coupling\nUnsupervised DA') + +pl.subplot(1, 2, 2) +pl.imshow(ot_sinkhorn_semi.coupling_, interpolation='nearest') +pl.xticks([]) +pl.yticks([]) +pl.title('Optimal coupling\nSemi-supervised DA') + +pl.tight_layout() + + +############################################################################## +# Fig 3 : plot transported samples +# -------------------------------- + +# display transported samples +pl.figure(4, figsize=(8, 4)) +pl.subplot(1, 2, 1) +pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', + label='Target samples', alpha=0.5) +pl.scatter(transp_Xs_sinkhorn_un[:, 0], transp_Xs_sinkhorn_un[:, 1], c=ys, + marker='+', label='Transp samples', s=30) +pl.title('Transported samples\nEmdTransport') +pl.legend(loc=0) +pl.xticks([]) +pl.yticks([]) + +pl.subplot(1, 2, 2) +pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', + label='Target samples', alpha=0.5) +pl.scatter(transp_Xs_sinkhorn_semi[:, 0], transp_Xs_sinkhorn_semi[:, 1], c=ys, + marker='+', label='Transp samples', s=30) +pl.title('Transported samples\nSinkhornTransport') +pl.xticks([]) +pl.yticks([]) + +pl.tight_layout() +pl.show() diff --git a/notebooks/plot_gromov.ipynb b/notebooks/plot_gromov.ipynb new file mode 100644 index 0000000..11c19d3 --- /dev/null +++ b/notebooks/plot_gromov.ipynb @@ -0,0 +1,231 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "# Gromov-Wasserstein example\n", + "\n", + "\n", + "This example is designed to show how to use the Gromov-Wassertsein distance\n", + "computation in POT.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Author: Erwan Vautier \r\n", + "# Nicolas Courty \r\n", + "#\r\n", + "# License: MIT License\r\n", + "\r\n", + "import scipy as sp\r\n", + "import numpy as np\r\n", + "import matplotlib.pylab as pl\r\n", + "from mpl_toolkits.mplot3d import Axes3D # noqa\r\n", + "import ot" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Sample two Gaussian distributions (2D and 3D)\r\n", + " ---------------------------------------------\r\n", + "\r\n", + " The Gromov-Wasserstein distance allows to compute distances with samples that\r\n", + " do not belong to the same metric space. For demonstration purpose, we sample\r\n", + " two Gaussian distributions in 2- and 3-dimensional spaces.\r\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "n_samples = 30 # nb samples\r\n", + "\r\n", + "mu_s = np.array([0, 0])\r\n", + "cov_s = np.array([[1, 0], [0, 1]])\r\n", + "\r\n", + "mu_t = np.array([4, 4, 4])\r\n", + "cov_t = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])\r\n", + "\r\n", + "\r\n", + "xs = ot.datasets.get_2D_samples_gauss(n_samples, mu_s, cov_s)\r\n", + "P = sp.linalg.sqrtm(cov_t)\r\n", + "xt = np.random.randn(n_samples, 3).dot(P) + mu_t" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plotting the distributions\r\n", + "--------------------------\r\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig = pl.figure()\r\n", + "ax1 = fig.add_subplot(121)\r\n", + "ax1.plot(xs[:, 0], xs[:, 1], '+b', label='Source samples')\r\n", + "ax2 = fig.add_subplot(122, projection='3d')\r\n", + "ax2.scatter(xt[:, 0], xt[:, 1], xt[:, 2], color='r')\r\n", + "pl.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Compute distance kernels, normalize them and then display\r\n", + "---------------------------------------------------------\r\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "C1 = sp.spatial.distance.cdist(xs, xs)\r\n", + "C2 = sp.spatial.distance.cdist(xt, xt)\r\n", + "\r\n", + "C1 /= C1.max()\r\n", + "C2 /= C2.max()\r\n", + "\r\n", + "pl.figure()\r\n", + "pl.subplot(121)\r\n", + "pl.imshow(C1)\r\n", + "pl.subplot(122)\r\n", + "pl.imshow(C2)\r\n", + "pl.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Compute Gromov-Wasserstein plans and distance\r\n", + "---------------------------------------------\r\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Gromov-Wasserstein distances between the distribution: 0.201997813845\n" + ] + }, + { + "data": { + "image/png": "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\nTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "p = ot.unif(n_samples)\r\n", + "q = ot.unif(n_samples)\r\n", + "\r\n", + "gw = ot.gromov_wasserstein(C1, C2, p, q, 'square_loss', epsilon=5e-4)\r\n", + "gw_dist = ot.gromov_wasserstein2(C1, C2, p, q, 'square_loss', epsilon=5e-4)\r\n", + "\r\n", + "print('Gromov-Wasserstein distances between the distribution: ' + str(gw_dist))\r\n", + "\r\n", + "pl.figure()\r\n", + "pl.imshow(gw, cmap='jet')\r\n", + "pl.colorbar()\r\n", + "pl.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/notebooks/plot_gromov_barycenter.ipynb b/notebooks/plot_gromov_barycenter.ipynb new file mode 100644 index 0000000..8102bcf --- /dev/null +++ b/notebooks/plot_gromov_barycenter.ipynb @@ -0,0 +1,368 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "# Gromov-Wasserstein Barycenter example\n", + "\n", + "\n", + "This example is designed to show how to use the Gromov-Wasserstein distance\n", + "computation in POT.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Author: Erwan Vautier \r\n", + "# Nicolas Courty \r\n", + "#\r\n", + "# License: MIT License\r\n", + "\r\n", + "\r\n", + "import numpy as np\r\n", + "import scipy as sp\r\n", + "\r\n", + "import scipy.ndimage as spi\r\n", + "import matplotlib.pylab as pl\r\n", + "from sklearn import manifold\r\n", + "from sklearn.decomposition import PCA\r\n", + "\r\n", + "import ot" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Smacof MDS\r\n", + " ----------\r\n", + "\r\n", + " This function allows to find an embedding of points given a dissimilarity matrix\r\n", + " that will be given by the output of the algorithm\r\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def smacof_mds(C, dim, max_iter=3000, eps=1e-9):\r\n", + " \"\"\"\r\n", + " Returns an interpolated point cloud following the dissimilarity matrix C\r\n", + " using SMACOF multidimensional scaling (MDS) in specific dimensionned\r\n", + " target space\r\n", + "\r\n", + " Parameters\r\n", + " ----------\r\n", + " C : ndarray, shape (ns, ns)\r\n", + " dissimilarity matrix\r\n", + " dim : int\r\n", + " dimension of the targeted space\r\n", + " max_iter : int\r\n", + " Maximum number of iterations of the SMACOF algorithm for a single run\r\n", + " eps : float\r\n", + " relative tolerance w.r.t stress to declare converge\r\n", + "\r\n", + " Returns\r\n", + " -------\r\n", + " npos : ndarray, shape (R, dim)\r\n", + " Embedded coordinates of the interpolated point cloud (defined with\r\n", + " one isometry)\r\n", + " \"\"\"\r\n", + "\r\n", + " rng = np.random.RandomState(seed=3)\r\n", + "\r\n", + " mds = manifold.MDS(\r\n", + " dim,\r\n", + " max_iter=max_iter,\r\n", + " eps=1e-9,\r\n", + " dissimilarity='precomputed',\r\n", + " n_init=1)\r\n", + " pos = mds.fit(C).embedding_\r\n", + "\r\n", + " nmds = manifold.MDS(\r\n", + " 2,\r\n", + " max_iter=max_iter,\r\n", + " eps=1e-9,\r\n", + " dissimilarity=\"precomputed\",\r\n", + " random_state=rng,\r\n", + " n_init=1)\r\n", + " npos = nmds.fit_transform(C, init=pos)\r\n", + "\r\n", + " return npos" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Data preparation\r\n", + " ----------------\r\n", + "\r\n", + " The four distributions are constructed from 4 simple images\r\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def im2mat(I):\r\n", + " \"\"\"Converts and image to matrix (one pixel per line)\"\"\"\r\n", + " return I.reshape((I.shape[0] * I.shape[1], I.shape[2]))\r\n", + "\r\n", + "\r\n", + "square = spi.imread('../data/square.png').astype(np.float64)[:, :, 2] / 256\r\n", + "cross = spi.imread('../data/cross.png').astype(np.float64)[:, :, 2] / 256\r\n", + "triangle = spi.imread('../data/triangle.png').astype(np.float64)[:, :, 2] / 256\r\n", + "star = spi.imread('../data/star.png').astype(np.float64)[:, :, 2] / 256\r\n", + "\r\n", + "shapes = [square, cross, triangle, star]\r\n", + "\r\n", + "S = 4\r\n", + "xs = [[] for i in range(S)]\r\n", + "\r\n", + "\r\n", + "for nb in range(4):\r\n", + " for i in range(8):\r\n", + " for j in range(8):\r\n", + " if shapes[nb][i, j] < 0.95:\r\n", + " xs[nb].append([j, 8 - i])\r\n", + "\r\n", + "xs = np.array([np.array(xs[0]), np.array(xs[1]),\r\n", + " np.array(xs[2]), np.array(xs[3])])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Barycenter computation\r\n", + "----------------------\r\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ns = [len(xs[s]) for s in range(S)]\r\n", + "n_samples = 30\r\n", + "\r\n", + "\"\"\"Compute all distances matrices for the four shapes\"\"\"\r\n", + "Cs = [sp.spatial.distance.cdist(xs[s], xs[s]) for s in range(S)]\r\n", + "Cs = [cs / cs.max() for cs in Cs]\r\n", + "\r\n", + "ps = [ot.unif(ns[s]) for s in range(S)]\r\n", + "p = ot.unif(n_samples)\r\n", + "\r\n", + "\r\n", + "lambdast = [[float(i) / 3, float(3 - i) / 3] for i in [1, 2]]\r\n", + "\r\n", + "Ct01 = [0 for i in range(2)]\r\n", + "for i in range(2):\r\n", + " Ct01[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[0], Cs[1]],\r\n", + " [ps[0], ps[1]\r\n", + " ], p, lambdast[i], 'square_loss', 5e-4,\r\n", + " max_iter=100, tol=1e-3)\r\n", + "\r\n", + "Ct02 = [0 for i in range(2)]\r\n", + "for i in range(2):\r\n", + " Ct02[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[0], Cs[2]],\r\n", + " [ps[0], ps[2]\r\n", + " ], p, lambdast[i], 'square_loss', 5e-4,\r\n", + " max_iter=100, tol=1e-3)\r\n", + "\r\n", + "Ct13 = [0 for i in range(2)]\r\n", + "for i in range(2):\r\n", + " Ct13[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[1], Cs[3]],\r\n", + " [ps[1], ps[3]\r\n", + " ], p, lambdast[i], 'square_loss', 5e-4,\r\n", + " max_iter=100, tol=1e-3)\r\n", + "\r\n", + "Ct23 = [0 for i in range(2)]\r\n", + "for i in range(2):\r\n", + " Ct23[i] = ot.gromov.gromov_barycenters(n_samples, [Cs[2], Cs[3]],\r\n", + " [ps[2], ps[3]\r\n", + " ], p, lambdast[i], 'square_loss', 5e-4,\r\n", + " max_iter=100, tol=1e-3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Visualization\r\n", + " -------------\r\n", + "\r\n", + " The PCA helps in getting consistency between the rotations\r\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\nLzLFtqgTIcnUwIOTZKwvdXu2mJemGPl1x6bYADaZVgq99ECTugYUNttMPRlzj7vyYQoJ/CJTbIta\n6TKZGnhwkozFtCzQUl0kasTXHZtiAxhzZCzWdaIGFjbbkIw1UxUzA7icUyem2BY11nUyNfDgJBmL\npYs5n6pEKnZwZf7NYacpNoAx14zFOr9jYGGzzRSSsbrfx+psN/DBh85MsS1qrOtkauDBSTIWS9+X\npahT56J99pncdWyqDWCssyljneA0sLDZZuzJWN1mJ9Z2sWJqaNPeU22LGuk6mWLNWH4lSeD2fVmK\nrf3FPLUu828OO9EAhovR6Q0sbLYZezJW97Np8hl2uca67ja5oS2qoY9kirMp8ypZjow1VXe4oW5w\nxU7uMjDFBjDmlFPMY4oRNinaybEnY3Wbkb5GN+s0Q0NM7qfYFjU28mQqFMlYLLHPXMw9ucvA1BrA\n2FNOTeoNnVaq836K7wFjT8ZijYzFahbqNENDnPaeWlvUWmggjThZIxmLKeaZi7kndxmYWgOYasop\nNEnKeYZ87MlYjAS+yT5CTwCou82yvzdFXzy1tqi1Lue4BzazsxPJWCp1pw1TJneZm1oDGHvKqa8k\nqc4+Uo2GjD0Zcw+f2o65wqHLNWMpm7jRtEUxhri7SqZCF/hnjmQslRSXpRjwEO4io2kAa4o9MhYj\nSaoTUnVCnZGx7rX97x/78wuZ9s518H8UbVFostR1MjXw64hVSZ6MSbpR0rOSjkk6uOD9CyTdV7z/\niKT9VfvMpfGL3nIs29/AA7GN+eAddRwVYq8ZC+1k69YTc2Qltq5jyDOJo5B/31xGNqv+hpRN4Cja\notBkqetkipGx0tLql7btQNol6XlJV0s6X9Ljkq7bsc2nJN1ZPL5V0n1V+82h8Ys+bRj6raNsnwMe\nKdsK3lHH0Q6hU07zQpOkuiEXc81RbF3HkGcSR6HrsGJNZ4fMcuXcF4+iLQpNlriOWJDUydi7JT0w\n9/xzkj63Y5sHJL27eLxb0i8k2bL95tD4RZ82DA3UnQYeuO7bGsDxxlGHQpOkJiMRueb9XceQZxJH\noaNGMU70CO1L60yZp14zNui2qOuRsRjJVOiatoylTsY+LOmuuecflfTFHds8KenKuefPS7p02X5z\naPyij5mnuKhs5uYawPHGUYlYbU7IfmKHUOKRsU5iyDOJo9hruhap+r0++vq9e3/3+t69/fXFo2iL\n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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "clf = PCA(n_components=2)\r\n", + "npos = [0, 0, 0, 0]\r\n", + "npos = [smacof_mds(Cs[s], 2) for s in range(S)]\r\n", + "\r\n", + "npost01 = [0, 0]\r\n", + "npost01 = [smacof_mds(Ct01[s], 2) for s in range(2)]\r\n", + "npost01 = [clf.fit_transform(npost01[s]) for s in range(2)]\r\n", + "\r\n", + "npost02 = [0, 0]\r\n", + "npost02 = [smacof_mds(Ct02[s], 2) for s in range(2)]\r\n", + "npost02 = [clf.fit_transform(npost02[s]) for s in range(2)]\r\n", + "\r\n", + "npost13 = [0, 0]\r\n", + "npost13 = [smacof_mds(Ct13[s], 2) for s in range(2)]\r\n", + "npost13 = [clf.fit_transform(npost13[s]) for s in range(2)]\r\n", + "\r\n", + "npost23 = [0, 0]\r\n", + "npost23 = [smacof_mds(Ct23[s], 2) for s in range(2)]\r\n", + "npost23 = [clf.fit_transform(npost23[s]) for s in range(2)]\r\n", + "\r\n", + "\r\n", + "fig = pl.figure(figsize=(10, 10))\r\n", + "\r\n", + "ax1 = pl.subplot2grid((4, 4), (0, 0))\r\n", + "pl.xlim((-1, 1))\r\n", + "pl.ylim((-1, 1))\r\n", + "ax1.scatter(npos[0][:, 0], npos[0][:, 1], color='r')\r\n", + "\r\n", + "ax2 = pl.subplot2grid((4, 4), (0, 1))\r\n", + "pl.xlim((-1, 1))\r\n", + "pl.ylim((-1, 1))\r\n", + "ax2.scatter(npost01[1][:, 0], npost01[1][:, 1], color='b')\r\n", + "\r\n", + "ax3 = pl.subplot2grid((4, 4), (0, 2))\r\n", + "pl.xlim((-1, 1))\r\n", + "pl.ylim((-1, 1))\r\n", + "ax3.scatter(npost01[0][:, 0], npost01[0][:, 1], color='b')\r\n", + "\r\n", + "ax4 = pl.subplot2grid((4, 4), (0, 3))\r\n", + "pl.xlim((-1, 1))\r\n", + "pl.ylim((-1, 1))\r\n", + "ax4.scatter(npos[1][:, 0], npos[1][:, 1], color='r')\r\n", + "\r\n", + "ax5 = pl.subplot2grid((4, 4), (1, 0))\r\n", + "pl.xlim((-1, 1))\r\n", + "pl.ylim((-1, 1))\r\n", + "ax5.scatter(npost02[1][:, 0], npost02[1][:, 1], color='b')\r\n", + "\r\n", + "ax6 = pl.subplot2grid((4, 4), (1, 3))\r\n", + "pl.xlim((-1, 1))\r\n", + "pl.ylim((-1, 1))\r\n", + "ax6.scatter(npost13[1][:, 0], npost13[1][:, 1], color='b')\r\n", + "\r\n", + "ax7 = pl.subplot2grid((4, 4), (2, 0))\r\n", + "pl.xlim((-1, 1))\r\n", + "pl.ylim((-1, 1))\r\n", + "ax7.scatter(npost02[0][:, 0], npost02[0][:, 1], color='b')\r\n", + "\r\n", + "ax8 = pl.subplot2grid((4, 4), (2, 3))\r\n", + "pl.xlim((-1, 1))\r\n", + "pl.ylim((-1, 1))\r\n", + "ax8.scatter(npost13[0][:, 0], npost13[0][:, 1], color='b')\r\n", + "\r\n", + "ax9 = pl.subplot2grid((4, 4), (3, 0))\r\n", + "pl.xlim((-1, 1))\r\n", + "pl.ylim((-1, 1))\r\n", + "ax9.scatter(npos[2][:, 0], npos[2][:, 1], color='r')\r\n", + "\r\n", + "ax10 = pl.subplot2grid((4, 4), (3, 1))\r\n", + "pl.xlim((-1, 1))\r\n", + "pl.ylim((-1, 1))\r\n", + "ax10.scatter(npost23[1][:, 0], npost23[1][:, 1], color='b')\r\n", + "\r\n", + "ax11 = pl.subplot2grid((4, 4), (3, 2))\r\n", + "pl.xlim((-1, 1))\r\n", + "pl.ylim((-1, 1))\r\n", + "ax11.scatter(npost23[0][:, 0], npost23[0][:, 1], color='b')\r\n", + "\r\n", + "ax12 = pl.subplot2grid((4, 4), (3, 3))\r\n", + "pl.xlim((-1, 1))\r\n", + "pl.ylim((-1, 1))\r\n", + "ax12.scatter(npos[3][:, 0], npos[3][:, 1], color='r')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/notebooks/plot_otda_semi_supervised.ipynb b/notebooks/plot_otda_semi_supervised.ipynb new file mode 100644 index 0000000..6c538e9 --- /dev/null +++ b/notebooks/plot_otda_semi_supervised.ipynb @@ -0,0 +1,294 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "# OTDA unsupervised vs semi-supervised setting\n", + "\n", + "\n", + "This example introduces a semi supervised domain adaptation in a 2D setting.\n", + "It explicits the problem of semi supervised domain adaptation and introduces\n", + "some optimal transport approaches to solve it.\n", + "\n", + "Quantities such as optimal couplings, greater coupling coefficients and\n", + "transported samples are represented in order to give a visual understanding\n", + "of what the transport methods are doing.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Authors: Remi Flamary \n", + "# Stanislas Chambon \n", + "#\n", + "# License: MIT License\n", + "\n", + "import matplotlib.pylab as pl\n", + "import ot" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Generate data\n", + "-------------\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "n_samples_source = 150\n", + "n_samples_target = 150\n", + "\n", + "Xs, ys = ot.datasets.get_data_classif('3gauss', n_samples_source)\n", + "Xt, yt = ot.datasets.get_data_classif('3gauss2', n_samples_target)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Transport source samples onto target samples\n", + "--------------------------------------------\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# unsupervised domain adaptation\n", + "ot_sinkhorn_un = ot.da.SinkhornTransport(reg_e=1e-1)\n", + "ot_sinkhorn_un.fit(Xs=Xs, Xt=Xt)\n", + "transp_Xs_sinkhorn_un = ot_sinkhorn_un.transform(Xs=Xs)\n", + "\n", + "# semi-supervised domain adaptation\n", + "ot_sinkhorn_semi = ot.da.SinkhornTransport(reg_e=1e-1)\n", + "ot_sinkhorn_semi.fit(Xs=Xs, Xt=Xt, ys=ys, yt=yt)\n", + "transp_Xs_sinkhorn_semi = ot_sinkhorn_semi.transform(Xs=Xs)\n", + "\n", + "# semi supervised DA uses available labaled target samples to modify the cost\n", + "# matrix involved in the OT problem. The cost of transporting a source sample\n", + "# of class A onto a target sample of class B != A is set to infinite, or a\n", + "# very large value\n", + "\n", + "# note that in the present case we consider that all the target samples are\n", + "# labeled. For daily applications, some target sample might not have labels,\n", + "# in this case the element of yt corresponding to these samples should be\n", + "# filled with -1.\n", + "\n", + "# Warning: we recall that -1 cannot be used as a class label" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Fig 1 : plots source and target samples + matrix of pairwise distance\n", + "---------------------------------------------------------------------\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\nq4hIBmv0W8s/EBGRyYa229rVe5u19V7MvvDP4En3tvb/l/r88D7dyd4REZH0q+fa5iOPbsuuonlL\na7p29jJFRpd/pmuGR/6886E75c6ffCYiIp3Hev8nP9H1+9f3PhYRkWv/5wMREVm5s+XO+b2b/1xE\nRD78E+1Dgb1jfFev0P4KiJvlqgPNOxnfFRGR5JEi1Bv7WGfgpebptjtl/c+033kHqgvQ+Y4OFPVr\n7l3TuTjwGSWqOPQfle+701vGGj3e2XTnJF8qor7deVueX7xGFYs0lXh9TYpemeMan/jxub34llqE\nF1RugAU96w7ylt+LF+Dn1756ocdiT3R7PvdGu3fe1LmlSsvsru79MbI5Ee5tvOkR18UyaiF2gG5P\nyhnGaEvbsBr76XK/NA7qUKedVulcy3UuuuVaATcOZvFQdxIbpLpoI0NKfnINqh/QbnbZyX3/rMdr\n+P65DnT5GPt0ErCpECHe9AhPaYgQIUKECBEiRIgQJl6NikW9JsXtbcmdni8/8MhAcqJI12IdigAj\n/TV+cVd/oTeO9Vd5ZnRpY6AEdaAI+Yrn2Yp4NQProMbqe+rPshK98yUQRSB62YrXMD19TxGA1b/S\njk9vKjrSeKmoy4io1jee0zvfRl/oLLarCF+G8c1RNd8AwifiUUbqqDptTOc4Bf7ezKMwebeMfLFS\nP8ffFEhLYrSOCyAn8w2d22QMVPNQ+3j4O4r0Nc79vFF5YE5TKJppnen4yEmtDT3iSi7m+s/1pP1f\n1+v0nul8zeGKNrzmf4e1DxSZJBd50YjQFyC6OLS579HtyZKiV6f3oXAw0D70nuoxoy39vD40Ll6I\ndATEcK7tz5ahs4v7dvQ9P2+NU/AQATilAAzJRW0e67w2Dz2qNMcyqsO9jSoSrSNdQ/OONrb6uT9n\nvKX3fXhN56e9r33sPSYHWRvt3fBrtP0LRVrzn38tIiL9dT0231PEN6E27+a6O2exqX3Ivv5Gxwwn\nyuRTfZ2Bc5pERq2gD2ULcCY3/7V+lj14JCI+u3H7j022iJq4D57qy0LXV/OgrPMdf/HYnXLnD9/H\ndRThjZH5af0Uzxg4oItnz9055Nkv/1QR8QzcTznCAcjWbEwMbxQqCBwhawRy1h2ApxoBMRcRWQAB\nTI/LHH7qX1PNZuUTv3YyZGlqf/mlROOygsp3GXmrJqPvXXfa3V6A24+vtasLe3gHCh7g2h99rPe0\ns4NnpeOzYwnA09Vz3dPHN7E2ARxz/46m/hmcXNP2s4bO1/CGrvetv4DO8pLe49E1zw3e/ZEee/eP\n9Non7+tnK1/rnB78mr7e+LnPMJ3fIw9fO7P0UD8b3tL3+UwuPfY1MvXjsspMdk3nJ2uB499E/cTY\n7JGreH7GQIqxd2U1/dv/Ghxuox+9wBiHt3UuakNdw62nPuMXIkSINzMCghwiRIgQIUKECBEihInw\nH+QQIUKECBEiRIgQIUy8GorFbC7Rk5clSTMREZn7VGfuTCOQWgJ9okv7T1q1WntqpDSZRo4ozYaU\nMAvXSnJyAxSA4HX7VFO3BSWH5jRp8NSHlTFoAygGbKLgjYViHRpTGGm4+lk5RcaijgRC9imLPS78\ndVi64+TwTqPSOJ0kk5Gtiym5RHMJFndgrl3K2KR1KclUo+QdZOp4D1a+0HSiM/YQkcZaWXYor+l1\nkrFet3mUYtzmntZRMPhc789KX1OL9V2dm6yn/Wgc+3VBiTNa/5Iy4vrCYpwzXwiXwKhjZdEp9SE5\nUMpI7QR9Nxa/EQq6aMLB9ZWu69hpIBPlvlgzwukJ0sTJBdYseBQ1UDiah36uSQmiZfF0S1OpjT29\nL1kXxU3Pj9w56THk8I603eQc49nR1P5SX89pPvLnZAf6WfzefR3Olp7bQHERCyYnW/4+TtZ0DS59\no+ubslfxLRRPfQPZqp4/h5SEZEWfm/OPtRCtd4qCSBSH7v8tX9i38YcqpRhd02NpvnGxpddff6F9\nj2764rmdv6P9vf9jzD/6QIpSug85rzVP6aGE2OgdTfM3n6JgrOepKCIio+9dd/9uf4mC1DrT46Br\ngT7BPpcKcCEJWeAzGt44kxs8g4N3/NppQ/UueuuWyIOyLOF3GfF4Ju1Pnl2ymhZTkMuC1aUD0MRA\nUbt2in0BxYhF27fhbN6/UcpLZw9cLO5PNNowRXqdQ7SPQubWnt7LBOuBhbS9Qz+PtQu9t7WvdU1t\n7qMNrN1rp3pP4r1jd87aXkUyDXJyy3so3gTlIULxsL6AmRL2xmQX+x3urduxDP2owT2d64FmJXwG\n8ezk52bvWtL+L51g38FntkA6RIgQb2YEBDlEiBAhQoQIESJECBOvxigkyyQ7O3dFQO79hTEO4S9x\nynlR5o3mHzTEqPkuVeXPnGVoVPl/fWFE8GmSAUQoQbtEK4iiRsbUJAbqwUIb1ydKhcHS2Bp4yMhI\n2NmusA1nj22uQ8MToOfuM0pZXWGW4hsuHxNVrV2NnFxesUR1snK8P9nl62UtFKUMMVa8pnxYkVAq\nyVjYAmWmRBINO4o67luLdq5mGJTFIyJFJIcFiuyTKXTJejSEwWdE2pltYBtNPye8v0RWhWg6i0AX\nQIxmvnOzvn5GBNnNE/7kKMYprAUvjU4oJ3eF466ISHGFZTILB91coNBygbkvrH04itYu7sGU5Zb2\ndamJ4iscenbHP4MT1OstfQrkDs/NxX1Ff7uwFp7c9cW0jR09P0Nx6PH72pfeV9rYbEX7cfq+H87G\nBkxE7ut1zu5pGxe3dG5WPtfPJ9teeqz5sSKC+U1FBGcwTaEpTBf3qXboJQI5T8fv6zE3f4yC3BtA\ngfGMsJhTRCTBJHBOawNdFzXYHU9vQ4bLyMnVUIx58VYPbUA2jM+G64e/2b0/1fsyvtWX/Om3LILv\nIIr5QhZ7B84q3kmPmf3O2dJT/hGvY5gPVS2oRcTZ1GfIqjnDJ+5D3JPNXizMauHZSCc0eoKsIfZQ\nW9TYQoElsx0R+sg9LUHfMmMfHUECsaA5E6Ui2Qb2gHxm7LZpFIK93c2P7b8dlw0eQ2vrWvlrtLCZ\nU2QamdHi/MX115dlCBEixL9fBAQ5RIgQIUKECBEiRAgTr8YopJZKur4p4kwyyO8yckfkfDqDC0hq\ndRVVoph80TByZUAVk6cwTADvltyvgvJu1oyDyADazzYhK7YPziHRkY6XFsrWwHukVBrRXwrCQ/pK\nwDMWET9WBi1JgXoL+WmWa8Z2yderIsZEMVpNuRT8DO0TtSWXrRh4TnRE2+mqsQbF9UcYl+lbYw+8\nbvCf61NwnsdAWDp6vXhqkCharQKpqR+VTTJqE6A9S36ukzPMIXnjmJOqIUBhON41jD3eVOTT8ZVh\nfhDlMEaZG4Qfa8Pxvedl3jI58LGxc26/xNqgmQQMQ+rnkGgC+pie+OwBzRQijLV+DFOJCxgQEJk8\n8pJhEWxmY87xWdn4pLULAxFjykJJts5DzPWptlHbB+8RfNHauV+XcyDiEcxRFpBF6zzQ9mmR2zQG\nK7QHjmHysvaFcp6jI95j/bv8q3vunAJ27h3KMp4pmto61Dbih8pbbZ97pHrnUzUNiR9/qcfC7KN+\nCrQbvPZibrJQuL/r62Ub4Oi58ozJUV567OUgG7/SvpGrzXVBDnKD68/wRvlMdZEtcdzjUdkoZKN1\ny51D3mlz90LieQWF/A4jatQluXNHik55D0nPTcaLzy143zQGmaMOIZnoPM87/tmgHXrrl9jfsP9x\nv6a5ihikmsY+3ItHb+m6aD/SZ5B88GzVc8iH17UPnS9xv1LKreHYDW2Dz4yISNHC9wKza9zfiBwj\noxUPzf6Nzyi9eQkp4n7eblU/8WNk+z2s8wFqPQ49PzpGdmWxCcnNIyDvi8uSlCFChHizIiDIIUKE\nCBEiRIgQIUKYeDUc5PlCFnv7l963PFnH3wXKQ9SX4v/5mOjM5f+z5+R08VxywKwNrbsoBfKhjgCU\nbDGpiPcfevQ2nSiHcbGrSFSyAtH4E5hwkPd2buxoG2WLVfLOyJvm57lRsfjWQJ/JUc7tdarKIIyC\nPObKvIqIHCj6JjRSqMzX5Edv6bgmHsUY3ILZBmxyZ130Cc1nAJM6ex5RWbR1jntA+o9+TVGSzq4i\nrtNlWP/W/FzXh7CSdTxoQV8wj7j99TOvXkBjjcmyftg+ANq4rsjTvFfhSYtI/bTM764dwzwA/Fte\nf7zmH4FZH1bcJzpfjTOdn6MPoYAwqWEOPDqXs5D9RMd1fkfb6z3X+Zz29YBuz6gKEFG7pu8lc0XN\n2s9guPIb+kysGdOcOp4l9v/sLf1s+QHQMXCpjz7y1xld1+u8+4X2N72uKhKD93R992CzO/jBNXdO\nc18tcclLPX5f2+9+oX2iic75fT+ctY/Vunq4rffl8Ht6znRN+9Q6eFtEROZ9v0bj9xVJy967hbnQ\nc6d9GJ7c0LnoPPLPAlVR9n9Dx3j7J1C5uav9p0nF8LrZ1nJtP6/DkOZIn9MaOO7zDV1D0/eN5fhz\nfWZHt4Cw0uUdc0wTjr2/7RHWt8CHnq00veLDa4hiOpPs4ZPL7xuerMuMUQkHe1dtQ+99Dk5vzXJr\ngTJzH+W5TkEovwIRfQFEF7UP7ed6/5gNcfv3E78uOud39BiY26Q3VJFk8VKziOQxc68WEYk7VLHR\nPmTsI/bTGBmbrGL8UuqDawzKPB1df7m9Trts3+2aeK4LZFH5DhARWXzzWN97qu9lVEu5ar5ChAjx\nRkVAkEOECBEiRIgQIUKEMPFqdJCjSKJ6XaJ6Ge20Wo/8Ne+rnoEu0GaZyK+tnMYv8eyo/Ms/Sipq\nGZlRseD5tJKFnmvE6mugJ0RrRcTxYGPwo6sIC6OEIFT4w9VKZmobs03tG1AXKm1kZa6iU9iwfSPi\nUK2c5nxWlT7MNZ26BLjgnPvOQ/CxjSVvegF+L/iHVKAgn5Kax+mx0XUm/xAc0BVw/dIDRf2aPaAw\nBglNz4Hkk/dKzedpRQfZ8G/TU3Bal4CEnsKyG1rJNfLJzT2JRuXrUI+aPFm+Xz/xfNWc9rID8ojB\n744UcaXtbP3Q8B+BnlM7NoWtdw1a0M0uUOJds4Yx5uQCfEryN/dV93gN2sn1Rz4rk8H+uDZUFLh1\nCOvvAe5Xnei6X1NxRl45ed16X+qnyv8tMEdETG0/iz44zuBf83mqH+ixydiv0eSZ9rNR074tPYJO\nMK7feKqZjPia106ejoHKg9PcId+XyPFjWEQPjb43/k2+sssSkY/KtWOo6K0d7W8GrnkCi/sIOujR\nmiK/nSeegxyDr1tbbmKs2mAyxHrAc9Te8fbhjut+RVLru4wojiXutH2tB8LqsUdAXP1+jdfYL2j7\nHRktZaqwxNCedvsb6iWoICFWk577GN+7oesugQ64U/zpGh1j7KNJX+eW+vJxq8wFTpaXzIvyd0ri\n6lC4x+AZ7Xquc0RucUXxx+0XyGg6dFoHqX8qiktEqKXQNjOjl88MaYw6lhxayVESsKkQId70CE9p\niBAhQoQIESJEiBAmXg2CLKJIZ16p3raakjl1byvHUD+WKheZ4S3z2Io2ZVFU1B/s52yPv/aJCBDh\nIGfYIh2Vc1jV7Xi+7twrqtOrLnhsg13LLvftyn7b18bVy/UB70VxfuU4LZfOj6M8Zjf3VIqwKAa1\nUSlnitd5WkYhxbj8kfPrsgLVY8gJNnq+7hxcqCDqx3OIAlv+OvWV2U5UuY4754rxVH8DVpEbs5Ty\nb7kOtY3JPbVOh9Vjc7bPv3Hlr+2bm2tkBaJvn2uewz66vvAv3s8M3ztnooVzHJXPJYpVWgdUX8G1\nC+4QfE0lFrtz0E0N7bAPOY9x5/i+JSk1oPkZ248qr03fokq7rrGy7rDVoq624/jBlTXrdLhFpECf\nOE9xUh479Zgtt55zW8TR6waRdW+ocFxL+x37CtTUZe+IovJYo7QQoRghryLFVSWe/Iq9mHv7vNI+\n21pcoT7Dcyr99+6pJmsoleAe73SRK9e1favs7U6jnvut3Vddv/PS6+r3R7kvlVqRb5u3ECFCvHER\nEOQQIUKECBEiRIgQIUyE/yCHCBEiRIgQIUKECGHi1RiFxJEWa1RSnbZwzRWKQT7H2e2iiI4i/FHt\nCgtOFuPQQINpUZpkGGk4FpYwXc1ijGJAa9SyPbKISL4Fu1kUUMRcrnlrAAAgAElEQVSrWpRFM4F4\nDa9RKCXiiy4clQPt02CBRTK5KdiQSprQyQGxSJCpaJsOZSFNxViDKXxe18q8uZQpZY44TtyD2TaM\nUUZe1H+6iusUkH6CLFY6golAF2nlup/rrKH/7sCad7yp12vDaGO+rK9nRt6rgUK4GEVZpCSwL6QX\n2IVJea/xNooOUTBYxzgXsD+OTNo1ZgEh+hIjbT5fxrFIoV7cvGwEQNvtGowShtdwvSHHbkxmmihE\nQ1HjeBPXhXnJvKvvd0bGfrZdx3i0HRbaNVA0N1nTNmrHvoAwwlpsvqSBin5Wf3FW7nzuC+HiBZ6l\nPV23vP9sI4MpSLLii81ooBIda7v9JyiGwtpncVT/oTkH65mmJc1lvW6BNUlznvquN39Jv4Sc3LEa\neSS4lyyDpUGNHBqDFTyz3ZeQ88KzlZCGgb4vfeMLuOJTLQSLLyC/CHttGqLUSPEw1uYC45sW9y+k\n/Z19Oc6hnKGIly5rPDuReGYoA991xLFEva7fW1i4ZgqocxTHsRiP+2h2Q225k2NYTts5ETYH2okt\nkhNfTGdpBtzrScHKlmGQAyMNJ4lpip9H93Qvbh1AovK6SnDGL7UQNL+lhaDx45f+4uuwW+e10X68\npH2kGVW07w08aBxEq2navMc0R+H8GfoHCwVpXuPmGOukODgqjdf+280FaULn/lkIESLEmxkBQQ4R\nIkSIECFChAgRwsSrMQrJcjXRiMsIcskC2km24Vc8jx1UfkkbNDiul9Fka9Rh2ywdQ8SWBRqUEkJb\nRG/zE4+88RiitIuXu2gDKOeTZ3qcQQasUL2Il4TLD48q4/HFGEQgiArnlMHLv8V6WkTk32E0ckk+\nT8wYOdc0ZQGqTbSW6KqIL0hqwip5ChQwawIxmut8UgJNRCSCe0jRhATUAmg6i5jQZm1okN0FCxHx\nulq4yDG0jGUyUFiaiTjkG9ehZXNmbKOTc8wtCwVpZV7D+kJfm0ceRR9tQQoMcm7JBZDPIaxs0VXO\nhY4Hxw4hDTevo6+4Hovq6n6tUq6sfsJsADIiQL1ZiCeZuQ4yFrt/V61rh+qnIP0Hm2Lj7B3/7/mm\n9r//WG2h0wN91vbQxiYK004+8mhg74mifNMVHcfzf6R9uX+qbYzX9f3jf+xte5ceKKp38n671If8\nrh7T2VW0eHDL359/8k//QkREfvbjX9d217QvFzdi9Fnbam4bGT4UxT3/XT3m/c/VBGT8tiKfNH95\n/rt+7az9QqXF5m0YhZzrwuu80Dk4u3vZ/KF5qOj46dvaTorHsz4sG4Xs/H2/rj/8md6Qw9/cksXR\nFVmw7yiKxUKy/QNnznHJUEj8nrHgvkbTDyCgPLKEhDbLaLLb/5xc52VDo8UeDIu4/9Cog4ZIU8jz\n7ey6c5o4hpKX8quHGAaehU90f8+t8cnXZRlQynFmGN9V+2qyXJayy2E5nQ+RkbvCsMoZL31LUNLN\nzoWT34QdOw2lKGMXIkSINzcCghwiRIgQIUKECBEihIlXw0FOE0mWV/9GoxAnYVaxaI5o8kBJIYMa\nk+snO8o/i3kskeOsLHkmIiLkKfO9TUWKBIYE5EVHRgC+WIKAPLiaUpE9iiAwXxi76ip67RAacp/J\nbZx5xNX1G6hC8i1tlIxCiABVxOndPAJpIa9QxCAZELAvRkBqMOcJzD6isb8/3UVZcs4hojQOAW+W\nhhgiIjF5w88VAWoBSU4OdK7TI71fed9zdmnqEFHOCfPk+kJ++bk3bmif6niy9X65DyeKJqU9HWdq\nJaZgPFLwOpjzOm1tybW94S2G+w8wZiDS0UjPaR3oXKcX4NoeXWGWMgRa+kLbTw7BZx8B4X954M4h\nPz0FqhxdwKwA66/fwTkHHrFa7Ov5G3+l67n/ROe0uaPzxPvTfemfwdmStl97qvcnA1K32cba+ea5\niIisnhvjE5jy1Hq65re7t0VEpP5Qn8H6Y13fF9u33DnJLz7Rvp2qLXD/qd6nwS3tY+unX2lfX2y4\nc/7FB39bRETe++tHIiLSBne/d12RvfoTPItzj/Dz+bjRVJ/rAlzTFviv5OdvLPu+Lf1ULYodn5ZS\nYzh3aaQ21bGdA3C1N0+0v+RDR0AZnTX83Ft058g6LX/Zk2RyhRzkdxRRrSbp9nUpOmVuvTXecXtj\nu3xMtgSO8Kz8zIuILBrg5X+pqGzK2hEYiDh5NnO/pEerbv1seleR/vpzXWMJ0Nti2WcJWB/ReACT\nHPLLWW+ytnxpPAW/M4hmY0+MKU3IPX/k92/33OKeJs2K4QnNoqxRCM/lZ5Q3JMcZxks2i5is6/Oa\nr+kzkZxgX7tKMjREiBBvVAQEOUSIECFChAgRIkQIE6/GKKQQkSwro6UiJVOGYkiVCiAO+BVeoII+\nItps7YKJjuKzqA+kl2LubMMgyLET8wdqwF/15CbTfCH16GneXi31Id5S5CgHJ0+APhWofBcx6htU\npqAKB5A3h6yMPeJawO7aIcVA3F01N21bZx6FIdrozTjKPO+c6LAxHaFNqkPjgRwTZZ781ts6BRd+\n3kZb6At9AHBqbaxvzKBi0TwxCg4NvVd9zMHpB4r+dJagXgEEc7rk+9yE4gX5yo6nDHSWKhb1I48q\nTdf0nOGNOtpQxKa1p3+nq41SmyIiyQS8xxn+wjZ6cg3oOviq53ctWq9/UnCd60M99/h9qEoM9G/7\nwJ/DOaifKdJ0sQ3Vij09Zt7VsfeMEUUGZO7iuh5TP9c108b9OsY8Lqf++UnIZQTanMyAMgPlTgd6\nzxeddX8d3n5yJ1lRP8YzQVTOqBVEUGwhYlc/1zmg6kO8oYhY69DwyvEs0GSBY3b3Y0U5zs4oQkSa\nB0D3qALThq0zMxYrOifR0x3fN2RyyAGnckTCrAqewdaef7ZdFooZK3JN0Zf4SPcFi2IKVR6GrBEo\n26K7rIfxhSDXNN07LY3ztURReLSUpjOWs0tFHyLImLccVuAx1lg08+uvBhUWt8+tlTN/Bbi71sAj\npiIR7aNHZUt1PutRw2Y9dP3Vsa/l925oW4+Uw7ug3fyuz8jINjITNOU4RX3Juu7rOe3ez0y9C74P\nMtw3p5DEmo4lWl2brCERcfcdUtmLzfcDgxbfEdY3a2OuOjZEiBBvVgQEOUSIECFChAgRIkQIE69I\nxSKT7PTscrWw1cQESpof4Jc/j6WKxRU2nV7LExa2lSri6uciItnpabk9nBOT7waU2yGvIhIBWciJ\nBrPieAHE4yF4s8YyefH8RbkvVLHY2y+Pz0RMdKKqYlEAlblCB1mqVdVEiqnSwTYNn9mpWIC3ymOp\nYkGOpLVRJRLaOoQixIr2ZdYBpxqIa21o0DH4DefdZmmc1EdeQCO4NjK2sEQM6RKNdp3NM/4uuh5V\nmq7odZySBlQmMvAi+f6i7RGdFAoUOVQrYqB61C2mIkXzxM/1xbae3zgHV3us/U5H5bVp5y0dl+cl\nwpwkUygeQE86M3zOBGhc44wWzfo+OZ9ZeTq1XWhzv/gPVZVh8BY0f7/aLo3n9EPTt2u6bnvP39PX\nJ7rOXvwDRda2/1xRwP3vd905vac6b0T/X/6+juut2fsiInJxTfs4+o+9CkzrUPtw/J6uxbMPtDNL\nt/VZPB8rwje87u/Pf/bP/pWIiPzRV7+r7W3ofRlt63x1n+k4Ojc8spu19Jjnv69j/+CBKmtcvLeG\nOdBzXvyOfxaWv9AxLqBi0TxRhL37Qp+989s62Zkpn+jsK+J9ep/3EvcY1HNaXR/9jkeq3/+l8qL3\nf3tDFv/isqLDdxXFfC6LlzuX9wsT3H+Kbx7rG9SrhtZ1RvUhm81jtgt71KX9j5+bcxYvoFXMveoZ\nJg61EdTlLoxWfAd9IMIf/VJVLDJm936s6y43e35R+V7gPpc/eFQah8X1E9RpUPGC2TXWPrDWo7DZ\ngMPD0hw4ZQ2qdICvXFKx4BjZF8xFULEIEeLNj4AghwgRIkSIECFChAhh4tWoWLSaEr/9vv/vNn6x\nF5ZDeQjO1yZ4btCCHd3T140DfZ03jF4sdHrT58pZy9eh1wqumas8N7y3HIoURVPbmYMP2/wSXEbw\nPPMlX518/LG2u/bnWok+vg+e5SOtth69o4hb5wvPe5vdUESPjmzpC0UxFpva1rwPvuyOV2OIzsDT\ng8JCCq4zOaB5Czq8A897y5ZRIT3HGDGnBYCa5EVFd1nEcf6o+uDc5Pa0j0cfkvvq0cbJmjY4vFHW\ncK0DKJzi8/G6hzdzUFc3RzrW8zvsm15/1tNzRtf8OmjtQ+VhBh4pObzoC8fV3vdIVAYU9vRtbWe8\noRfuP1V052JL20xNof6sr/NGPnGyBPe6NfC9gTYef+SvUxvovyerqNgf6t+zD/U69WOgZy2/RhdY\nRvUzOunp6zmUIuYAQNd+6fs2vq9zOLwB1P4ACP9Uz3H34rbX6F2CKsb1//ULfWMbXGMovFAxZuve\nbX+dW1D9+Dc/0TeAmt2AokYOrubmsVd9IHe+9WNtd+kzXaPZ56pEsbahr1c+8/rL8VCfk2uf6fpe\n/Ujbi3Ltf31fP+//qder/ePH/0C79G90PD3wSKlmQg5y8cU37pwEnNL3v9G/2df6Wfu5PtvMyLz7\nyZYfT0WRhmMm93nlzzD3b/k5KF7oPtD5MyxwIqzknAJBXPnS873zh491fh4/k2T6/7L3JrG2ZFmW\n0Lbu9ve++/r3O/fvTXh4NB5NRVRmZGVmZVFZoqoQKiQQKgkYMWKIVCMQEnMmDJgwgSFCqEAIUBWk\nRFY2lV10mRkR3vv33//X9+++25oZg73WOdvsPffwKF4RKP7Zk/fvvWbHzjlmduzb2muvZS7E/4+j\n7Hdk/r2/4dVg8Jca0iIinad6nkav6fVA7fO9b0NJ5BmcMNuGg4xsyuB9zQpMX8XagvuoeYC6B6Ot\nPt/Qm2PR1fm6XNe/G3/K2g5da6ab/jp//jt6H73+P2sf976j18HqT8f4rNtu/ZnnE598Gdx0cN6X\nPtDfRm/o9+MVHcfwE18jk+wCKaZ6zhvKdc6RuZr3tR+NY7/PeBNcZmQU3JziT/+Dqh6ziIhALWP8\nqs4Ftdzbn36+pnKIECF++REQ5BAhQoQIESJEiBAhTIT/IIcIESJEiBAhQoQIYSIqrymO+0VjKVsv\nf2P535Ooi1QZaAe2+ILyZ5Qwo8UnJcmcOYaVI4LYfXR0WtnWSfFQRsgWtVGKibJYlK1iPygwH5si\nDxTusb0cFqnxUOkSNAjhZxGRksYckLJzphyQUHKGBG1TcTVEWpIybizggLh+gQKRxPS5YHscI6W6\nUFxCo5XSSBi580CzEtpt8xzADMKe+xjHdNvCFttJ9VFaz5xT0lUo/RSjkIxydk5GyojiX5ECZKEL\ni4lQfGOtcWmz7Kg7ZzpWFjM6CTxrMsPzg/Nc4NpJVmEMwsKhzOxDGUHOJc6P3EHKnmY2J0Yuiqls\nSoNtaNqdc8zzzzkS8XMQ96omBG7e7qoBRfnMS5xxHAf/+JvatQ09bvcFZPj6LG70uyww/Vt/oddX\n5wO1Bz7425pOXvmJ3lezFS/d14IhyPQ1pTw8/Eeacn7l/0LRFFLqT/9jf8+99Z9ruvj0u9pvprSP\n39Fz+vZ/q2n542/66/rX/4nSPt79T98REV9MeQT6z8YP9brPW349SGFe8+Qf6n306v+mczxfhiEN\nJAOf/pu+SOre7+k+LDqMcJl1n+r5Ov6qXluDx57WRIvv4y9ru83zqi05aUDbv+Xl8V77H3Rud/7u\nhnz0T/9rudx7eo1v/L/+WGpulX/rzn9YoZCJiEQ7hoq1Atk9SmBiDYnPUaiGz0XT3xvzZb2Om8/1\nmmFhM00y6oYhIuLXRkjrze7BtAn3cXYAypmRQCT1rqAs2qdP9HvS0bB+l7c9vSU+AA+M1LJVPafJ\nHp4bXHP6fk7mWzoHlBV0Bkak+MDyOrqz5cdzhALw+lqM9Skf9nBcT7UoIGPKMSZHoBqu6/F/7/v/\npYQIEeJfT0RR9KOyLL/7r7p/QJBDhAgRIkSIECFChDBxM0YhRekKz2xYhJImG0SKy3OgtrRxxv5W\nJsiJ+lNUnW/sNeMLiyA75BOIJEX7y2PIAxEttsgujAwKiM8T2aPIOxHM69BTN76jah+Jclvk0Bmf\nENGoo/csqDm/MN8Rwc2r20JaiGYmlBMSEYmJUParc1uOIVP0KsT3jdX0Yh3oNgr7CiAezna2peNN\nTzwKU8AqOX6kck7ze4rqZLuY676ei7zrEb30FP2smS8QuSmJOhmraaJUi7Ue+oCiHGYWiPwapDrm\ndVC376ZpBRDxGayNRUQEEnPJkh6P5iKjN3Sb9FLnvNHxyGHJOQDyNdvQvmSw3S5gG508P/DHaSqS\n6qyzcZwICoFEtxr2/GwrQrn6U0XuJpuwcX6u12gBpHW66vs2gVRf52d6fpgZWX4XiPwDtQ1uXvqC\nO6LYTSDJ6z+6q228Wy1y7f7Zbb/P6WMREel/hMLIu5RmA2qL8zR8zyOF//sf60v920AIeY5XC1jy\noigxHfn7h/fLynu4Bj/RfZvMMOBa2jRW063HiuY1gXBGXKcO9PuVmWYHaJ4iIhIBSV2bbmAfWBfj\nHPMaXV7z81Y8VtvujR915NPRL9FGuCikHI0lrq0tFenIHVyLyDTFx1WzFN6LsVmLs2OM/YVeh7wO\nmJErT7A2msyPs2nGfZlMtQ/JtmYcmBHkOiUiMr+t90b6sV6zlDd07a+hONoi4shGOjnLZyimpgFT\nh1k2v6bw3mJ20GU9mcniOn7s5QxdwSezXrycaTrzFJbuJ36fmLbUWHdoPBI/+uUVcoYIEeKLRUCQ\nQ4QIESJEiBAhQoQwcTMIsoginIuqxarlmzpxdSK4/ExeMd/gjRkH/+WQ6MXPt3B13NWiiiA7y1W2\nZaThaMta0qp0WrWYJQpc4WvXEHMi327M7IdFbmjmQVQY3GNnt0tx/MQjba49tpNXkVfLpa4Huc08\njpBvSw60EcEnohqDk+c4ugt8P8X3ZtwOpQLqQrSZfb2yrz0m0V6iMtyHc16YuS6u7wPPl+N0W3OW\n+twSVef8EdUae1tvSgwSMSRHk6Yf8YzHs2YpmCcgUtGsU23DmQqY642mB+PaecAcxJg3y8OmSQ1l\nCydDSNuNYHQBcxZ+LyIyXQKfm1z+Fi3AwScFslZ0fTYlOYNBQk9/m6xU2yibRKr9FBBNzPvazqyv\nfZgu43zguIslY2m9Mam0Szvg2VDbzw6wrc0o4dxxXAPyu8mDxb0wWfb3RB9jYxYjnoALint+PoB1\nsb12cE5nkAZMx1VLYR5nuuT3oQnQZKnhzG5+KVGWIvOZyII+41zT7FqMc0r0lJm5s1FlHzsKzijv\nSsoKXglz37LexGVxxrX7lNuadSg9wfMAa0rdwtrxpO1xkPVw5iisC+D4av0QEc+ZdusPMo00iyLy\nm5haFWYjOR62d40plN8J6wP6UM5xHrJfnplMiBAhvlgEBDlEiBAhQoQIESJECBM3gyCXZYX/6cKi\ngGkNwWXUEV6LuALxdCjcvIpuOp7YdUoc/M5xXbEt3/aNBatDjKmAQWUNIL4OMbjGztm1R/WNBVGR\neaVNEfGcOKIjeY1ffI0tLH8jYhLFVQSUlqjWBvuzUGWiIdH8KrpNtJdoS0STlxqSHBm0p6whJzQk\nkRpKG03tcfLKbx7BqX2+ziIX7TteeR2BSg3yXs825LXj1hFz8ZXmbhxol9xJN0emUp98eH4X1/Z1\n82URrxLbcK7zKmpOpYjKvQB0bA50dt6DagVMGGjrze/1NxwanOkYqBn3aQGBLYzxSYJ7jrbXNDph\nGyXsvWdLBhHHPouutrNoA+3uA70Hwjzv+uOsDaGk0gZXGxx3Wpt3qF5h0VjMLRU7IloKs2+47mcD\nYzLTqfYtwToUw5xn0dPfidqL+MwIzSKICEfwo2aWy8411Urm/fSXiyBLqddafT221xLrJ3jP1bN7\nDuG95h4k+uzuJ67FcaWtapewDrA93qfx1eO4bB7VbIBUO3tsIuG2BoSZJezjFJJc1q1WvyHi1uso\nhxKPy/hJdV8btfZ4R0d1RRw7B3zuOFtqbJteM08hQoT4/1UEBDlEiBAhQoQIESJECBM3giAX/bZM\nf+PrjnvIaB15fidRlxxIl/sMq2FqixIJE/E6rivva7V4CfRn0QbSB6QtmXkEYt4DMgAk9+xV/dzb\ngW31BVCooR86LVXbB4oiZOdQm2gklT5XgkAnxuGQxBqY7dBA0052kVe2dXbVp4qWTNe9Li3Ryxh/\n84wIHpAvWFC3dkZun8mWQofTZR1j66iKprbfU0WCCkf8mVanR0tQs4CWJ5VCnAa05YiDo5tDQSPZ\nVyWPAjrFEf9ueMJqCQ6hV5cAMmTUPkREiqnhOELVI9mCagAR1xG1jnENUe1EDIpEBAo2y1T9cNsN\nvCpH8mC7si/R8/QY1fano0qbIr5Cnsh3sntSHR8QsfzMK6Ak69BKrus6kyf98EWlDRGRCIhZ55ny\nLds7ei0RAR/f0XGs/9hUxwMVLYCi8iruPDRqLCKS/uyh3wX9TJEBWXkfCgMECB9qpf7g4zf9Pi/0\nuzZQufb7eq12d1QXOf9Y2/eGwiIvfqK6tqu7sJL+VPs9nL6qn/9ara2puCIiUsJWe/MH4C3Dej4+\nxvyBz9zZ9etB+pGqS2RUpiEfG9duOoYCwU8fuH2oWtOlQskJrjMqKeC6uFXcdftQezyZFQ5R/GXE\nl751X/7PH/53v7Tjh/jF4h+881+IiOF/m1jcUsWO5Bxc6gNdW8pbWE9tppAoPJRpqKUuB7C0RvYy\nf83rOqd7uJ7Jj0ZWhSourmmrqsR4E5b2eL5Fz6FusgpVIKP+4TwCqLFPVSise0TVp3/jdbdP61NV\nWqESkmB4kzu6HvF5F428elMB9SGXAcT6Gk0wPtRPyMPnvm+vqBrPYqjHyR7vV/oWrWA8hsP/z5//\nNxLi5YiAIIcIESJEiBAhQoQIYeJGEOR4lkvr6ak04bxEZCy+NEgbNYAHeMsDujVfAfICJMw6ZxEx\nbjzCWx3clRrkb1E72fBis37VQSrO8cb5+KSybWPZbzfZ0j50HkCfE3zICP3P1+DMdOzROVbdu+Pg\nLZ+cyro+ru6Et+1JjfNMbjB4rC3zVuzcqKCKUGLs6Tl4pUQ1zVt+e6QocGMFzk7oG5UW8s0h+uaR\nao4nB/eUvNjkTPeZwa3MKlKw3+mlzsv8NdWUzXagLgBEYrrpdU4bR0DwqK+MeXJIAK+dY+PCCJWC\n2SvqgpeMdC4SIHXFKlBve+7ZzrhWbb+kfSFqf3lv4H7KoGhARJpjvXhV220e69/s1J8fzldyqdfi\noq9jzk6AHAO9zeYmm4I+zNa1vQb5kLuKmuRvKmqa7noUpoCrHvWUnfYzUM3OBRB4w38soCqRfqio\nUn5wiE2QGTnU691pRItIhOr6HGh8ewe6rQ8UiSV6vvTYj8eNq6ZVm46AopOff+gdxnqP19EHOJYB\ntU8OtI2CLo3GTZA8UV6T8liRoJzcWaBkSwOvyuEyE+TbQqM2B5rV4DVkxpEDdUt4f1LFhoo7cRW9\nFxHJnyrq3619HyLE58XodWieH/u1eLas9yDVWmIUE7QOdK0a3dLfG0Zvmy6Sw2N9Dhx/S7NUg0+1\n3flA9zm979Uzesu456DSkyOT2jiuOpdm2z4zl+O5efw17UvzTJ9ZPSDYk7v6fXbWd/vw/wPJOdZn\n3HOLLTyH8H+Bo7f9OtRZVQS8wHKWXeo2h19DlmoPeuy7nivO+Wqe6rbjVejA7+n9OBvo5+HEr13T\nLV1Hz+/pvPRbirC3Hui2dAftPbwGRQ/xKx8BQQ4RIkSIECFChAgRwkT4D3KIECFChAgRIkSIECZu\nhGJRJrEsljsujcNo7vt/522khJFuKRqgDoDkP11Bit8UxM0h+ZSMNbVOWkbehpxOTFK+TzWRosHi\ntsmKfi4yTftmZ5puWRjJqRgpptkdpLteaJqX9stMAU3xu4inhJBmMFtGOntMKTL9O1/1af85CuvS\nEQrvZpQGg+QY0mOLdZ+eSkYoDmBBF+TXaLpQ4riNHT/3c9gdz/p6vCb6mN9C+utPfqafrVEI0uAp\n5JSc0QbS2mmzWrhmIwfFIkGB2AIC/Ux5N5/68ixaYhc0BkG6v1jUUvb2OAc69nQPFrnY1x0H31fa\noGkALLlJHSi5DdpvG/vw0th16756Xpae0SZ2XBmDiEjqJLP0OBmknkhFSDCvi0tPz4lAX2g8xTVP\ny3T0NcbnhSlUpHX2+a9rcczCFXzqvTG6pfPYPPXzRhpJsvWGiIj0/lrbGH1d04btF1rsExkqlIAq\nIG/dFxGR7d9E8V//S9r+jl6jT3/XUzne+gNInH1NC+widOHgm3q8Wz/T8z/95n23T/kPQK34Yy3M\nIe3o9JtaiLn0J/p5cX/T7ZNu6z6H39LU7ACGJzFSpouenuPnv+XT1ffPtJCORTg5JO0auzrHx1/T\ntpb/4oXbhzSw89eRRj7W9rP9avHS8Vc9PWe40HHs/vqyzP/Xqg19iBCfFZ0/eF9EDH1HRDpYa7uQ\nDmSxLtedForerpOvW4BCNPznuq7l51pslqV6TW78bOi2LbH20YSFVK+iZgKzKMxxIFu3+gjPQjxD\nWITc/BTSi3btwrG5PnMt4z1Pe+/be77olX1z6zjG2ntPqSNyBgMZQy3ssmAadM4uaVpYtzs0NDJW\n4I1tfdauv6v3PClfC/R1cKRrtVujQ7xUERDkECFChAgRIkSIECFM3JjVdFSUXuqMxWhGfN/9Bm2z\nqEAhFNBTiuuXC4OA8cW11h7bKp3WWrUfui+2pcxaTVLN9i3GMZ08E9FNFvbwuAbVtPtru3FlH/e3\nsFI8UmnHz1d1n4rBSs2cgiL+lLErs+jqPjxOXpuLsnp+KmYcRXXsV4KWzZ/1u0jVilu88UVlHx7T\n/f0FTBVcH6pzf22f6kYj15mwiFw/Xtrz5rW/5TXzVutTlFkBgbIAACAASURBVFTHd23frpuX6+I6\ntB7nO2+g8AWfC9zJuUni+HsM7cTM3uBeQ7FZxbSAphFE9ulYzPuTvzfNvcDvMhS1sa+suWEGo2Es\noFtAmNJ25bgFr2ci8cbql9tw7Lx0uE3Bv2YOaP5CycYio15ddd7KzBQH8zica+yTZlUZS/ZDRBzU\nUKYi8gtc0iFe8qgZQYmYdXpB+2usLc5UCfuYDGDdHKq+FtePZ9u9slZ91lp5Xb9rhkz1tbnablnt\nd/04s2sKf52BC7JreA46S/CK2VXNChz3tDeMucachZlSFlG751Jt/r7InIT4lYuAIIcIESJEiBAh\nQoQIYeJmEORIpEhjDwYCnaEElohHXMkT5FvyZF0/xzNIv7T9/9lL/JMcY3KPKf8WwSDE2fuK5xiS\ni0yuZnu/autbZJ4nON7QN8veE+V4LTYgG0YB8w1FudJLfxzHtwYql1yC29xhHxuV70VEMvybMmU0\nGXEIWJemE24XySEbFk+qKF3egtwb2rrONprzRPSMx43fBFf0wphz4G2bMj6UqopPlePlpNTyq8hE\nBLmt6B7E6Q8hqQc+c7617LYlz9rZRTcoqVfl/1puGftW3lMJnhgScQJZNFlewniMSUaNCxzVuMJE\nWOZveSOKbBecvFbVfni6pTy17BiSZ2beih7l73BOKe8HXq9r64mXK5MN5dHlQ+W9pXvKiSvBd5Mt\nlUBLjWB/Ad7y8AcweeG8QcauuwHTjDNzTokMA3XJd9Roo/9DzAGMVoqR36ecw6zkQzX3uN19S0RE\nGk9VIo5GK7d//x23D/mHjZ880j5h7rcmer4oL9f9S7/cPPtnyovufvRX2i6uh2X8XTzXcaaGu72A\n+cD6n2MNQb9LfJ+As3k7vufnAONokPcIY5pipO2uUG7w4RO3C2XvhsfK0abBQVnjIa7NX/Ef9nSM\n6z9M5MHo52QGQoRAzH/tbRERyY7NPYg15HILzx1cT409vf7Gd3U9qmQx8Sxp/eVjERGZfV3vgcYz\nmIvguj9/y9fRdF7AAIkSq3h2pSdV0yau5yJ+TR+9o2s9a26an2rBkTM3OfTrN6VP43Pcry08O13G\nFBJu3/P1Bv1HeBbTIh7P+pM39N7sbUOu9dgbeEwgj5eM8f8FPPsbp/NKW+2fPnP7zF/XNWq8Cd43\n5NySFxjPGxinkXgN8fJEQJBDhAgRIkSIECFChDBxM1bTaSyTjabMuoR89U/TKFKQ51u3o571yanV\nz4uOh0/JJWwfogK9CQWHFlBbcCvjqUc1p0NtPwaIc7kFBYSpNpaOdcjjFd+P6TLam0I4fVZFSacD\ncBCnfp86DzIFwkvB9hKbJmYf8qyzc0x77fUkHekbvLXBJg87maISGLzI6ZK22zjXvy3DYZts6Dgu\n18m7BAqNcXVQ9R8Z3qXjh5HzWV7PSS4ND9NxqRvVqv0orrbBcWsn4upfopw1Dp3YvhXV88E+UCXD\nmmO4bWBa43hptFEF6sgeEWXXbYGsxlAIyapk0oh2rrav5OY2SGYtq+MibzA1HNcWswxxdRuiwuiH\nNE0GBlbGjivLvhD5p2HJsUE5wenL14Eus/qd3OMelGUsMkqOe1pdGkqYtdC6trSnK66OlVXjRKbc\n2YvMXLMmAMextuc6PnDu216RIkLlOhHxYgjTF2QfaPtdNK5576dFOgxJXCYJaJblgMZAyWjK464v\nnnfOveFM0j437zQqduwhQnxe8JmWNux6BwQUz5jsgrUk1bWYWUQRU1vTqhpYuXudhjhmqeRa7+p/\nWEPANR77xCbbWufm5k1kNht8PiFbae71gsZbMF7Kl/Q+dcZb6GNu1lsqPJVQYuJxXC0Rac3mXnP1\nC1icoqLaR9ZRiHlezXvINDfxG7aJkI1yNVLNoEzzMkZAkEOECBEiRIgQIUKEMHEjCHJyOZfBj7ed\nFTQjOjPIFN5WO0TAiMZk1S4Uxmq6aOq/sycH1QPyDdBV+/o36w6RQnAZu89he4u3VaJN3a6xWcYx\n41NsQ04m0K0u3x7NW7E7dlRDGetVvOaN26GYtD9e1Kp7wYtsLnkdZOpMlkCrqDjQAaLH45GHKSLS\n31e+cBd6rrSjdtbW4LaWRqsy6isaR61ZomAl0AzXhtXIBLJGbmja0eMVQCSjFrShjWVyCZ6wq04m\ngjitam9areGYb/Mn0L6kljL0LGOixKaqmxzmgscB8sm2yEEmR083xlgPwAmGlXkjUk6w0ws+8/y6\nBNeT4zrD7ro8U/3RGHOQn5778aBP2dIAc6LzlXMegRaT7ysiUoCLW35ZuYWzJUU5Wwfg6nVwLt5a\nd/vkyLR0PwG3mvP2uvKu4ye7OoZbW34f8JQj9O30Db1P1r6vfYzXVHf57DUPRfWJsG4qt3oBfeKT\nt3Qcq58AXd1adfucflXn4A6uuwTHm76q7TfIvzYKGzHstS++ou30fwztYqBmRHwvN/wa0t3U+Shx\nv9P2VjgXtALf9PPG+2SOWoSkgwxMo1p3cPbOhp+DP/pYx/j6qj9GiBA/Jzofwzp+ZDiuq6pV3P8Y\n6yavJzwvmru6bXxdDcn2jn5cRnaIVu64z/oP/TM5OcSahHUzOcJajAwQVTMKoxscDzUb1WIf8Mws\nUQ/SmOiaaTNCCfrAZ1j8FNkhZF2ofLH8Yc/tw+da+ynWUa6zsd6n2Zm2n+55Hfv0HM+JM+1Tvob7\ndx/rOdYAu6520KfWpq478SH0o7kOMkv16LmEePkiIMghQoQIESJEiBAhQpi4MR1kEfG6qjUdRxGR\ncgClAVaeEwFFhWwJdCg2iGsBXlbZx7YnROHAd8IboeOGilypjI0vUcG6DMUA1yHDOXwGy781RZuL\nF4qsxVtAiNjHe77KNt4D0gp+Vr6m40v2sS1c3mTo3bbo5hV3WNUL7iRRWepRWlSd/FCnIQlNTDoY\nLetbeGLmwKlhOA1o/Zuv4G0Yb8cVTijOXXGk44qBOJCLRfSxNM5zrGhOcO6oKUlOMv+WJ34fpydJ\nhyQix+SS4XuihSIiEZDpktcO1BdiqA049LbjHfsEDlLso3Oqwj4R+7HrsxPlBhBOoL3cJz5sVvpo\ntT8dKotxJBwzEXBsa8dTYA4jZgXQp6TGEbaRbum19/B3dZvJhqIw7Rd6/mdLOMdtk7Fo6hjXvq/X\n9SpUYJ7+PbhH/VUL+3qUduk97efxVxXFuvx3tK/7saLD5P1/99/9qdtn5/feFBGRF7+t+8xwyWd/\nE65Un6hixc73/Pn5/X/4X4mIyH/0f/8T7Svm9uDb+vd2576IeK69iEjzWMf89N/SPtyfaoX5ZLmq\nj3zxbxu0fq5o+XSZvHj9M3is9+vBN/ReW9561e1DfvXRV8DzP9U57+wPK7/v/o7PXL15oPs/+7sN\nmb8XEOQQXyxKrLe2joK1CRGUFGRFrzunmEPk2KxdgnU6Wdf7tBwrwkoOP7OXyfaR36dWU1FHjtmn\nGG2KiBRAplnrwP7HrJFAposZKBGP2DKjWED1hn3m8zt94JV+8tc0q5XsAH1GRrD9rFXpczTxSDVV\njApsG2PMJdbzCBnBaMWrKuX7Oocxn8EYR8w557mQEC9jBAQ5RIgQIUKECBEiRAgT4T/IIUKECBEi\nRIgQIUKYuBGKRdlIZHZvVWZLVSmUtjEKmfch7l9oimbRhtHFuqYvWWSUG2m4aV//vfQIafe+pldo\nNkKJLkqxiHhJl3Ssqe3zu5pmSSeaW21CGofHFxFJb2nKmRJt7cVtERGZbYC+sKp/J2u+CDEbgHqA\nFMyiq+1l6BvNS2hcIiIyXYYQ+6X2N+G2U902hazX7I4Xc0+RVotohoLjzZYxFxhP21AsppucU922\nCZk8Sto0mU4qfIqYRXG0Daa5A+Wv+L213CydFSqKLmioQAoCJcMa/jpwxRv1IsfPskYVEUEaL0qz\nyvGkuKy2MboqVyagulBOLN/frzQdd7u+bzA8cVQXjh2UCNIobAEK+8R98j0U3SxAn6ANs6FlOAk1\nyjkdH1f6HJHOMjfHAXWj90T71N7Tc5tdaBuj2zjXpuYwWuBegAwiTUSWHuqYG2fax/a2n7cIhia9\nnt43h+9pqnR4rsfpvNC+/eGHX3L7vP1MzQmGD7RdyivtiqYyGw8+1d83PI3hP3v2j0REpPtM20su\ndazzrqY2u+/reYrf9Ond1jM9D8Of4LtS9+luY19c30ePPZ1l6YFeI7OhjsffE3ouWwc6R4MP/MSR\nCjWHbFz7SK+31j5oM7guZj1/nHiO9g4jJ1kZIsTPC5r0VO51FgHTIImmSTQ5YmGzXTO5NoF6Fx3V\nip8hxUgqhB4b6yefA5RrLGpGN7bo9DmezyyMZRE5C/nYxqGhcnD/82rh8uLh48phktUV9+/4J59g\nyFzrdawJqI3s+8IUN8bsE/d5pIYgbr1mobMtTidND+tz/hyFv6T6Ye3Pa0XkIV6OCAhyiBAhQoQI\nESJEiBAmbgRBjua5ZDunTmaFQVku/TcOBSmmzInv65/sBEViRuatCfS18QRvo3hjTk49IikiVTML\nmivgzbYXKxqbnugbYDxSFKjR8YLqFEaPL4A2guzf4NsxpdUujZkBJdogX5exaMCYB4iIWAuL9AQy\nNJQLI/JKgwogsA2DDLj2+BfoQQMWuW7bA4+AtWAEUvQpj6btZiz+Q8FYaY0OgJaxMIOFGpQ6owB9\nxdABaAFR2RgIAAv5uE9kUVqgvJT2iShWT1SbxYJGTo7IQExZNPxWsBCPZhLmOnAoQk1cP2YhH4s4\n1zxqwTku60YQWyhQo9SQkXmjdTGLMmm+QZk3FgXmBlEhahFD5oiFmMUFbE5Xl7HPsdsnx5wOHuvY\n531kA44gRXeBDI0ZLoXzu8+AsmxrcWZvVc+Hk09M/HtyDkQr29brqf9Y56v/CdAfSCi1Pr7tj8MC\nmheQq+tqXzq7Kcal33eeebTnLz56TUREvvpiT2z0n0EmD8hQ65GfAznWOeju6Py0H6D4B+hSA0U5\nS3f8OaXEYDxGERGuLxbTDttaDBSd+nOaYQ4GmZ739BQFmGY9ExHp7Hs0Ln2s41heb7lsVYgQPy8S\n2M6XJvsVQUqNxdrEbykPSrkySp+JiHuuLh6pZXp8T+9Pyq+5IroVk508gvwZ0FNaxDvJORTOFsZI\nKO5jzUJBc4xnJTOO8QDFeQYR51rPZweR74Tj5O/3vNxkhCLDmNKdeA7N3tRi5fREx54e+gJwFiKy\nTxxrTKtsPOPypy/8eFgYjedAcgRZzgOdt+gVSGI+8wWEIV6eCAhyiBAhQoQIESJEiBAmboaDnCUy\nv70kM9hCUuat0facZHJ1aQPrLJkpnQWLx0Xb850WbfCAJsPK8cjr5XHimefFkoeY4LuzV/StsgOO\ncwakjX3Vvunf7Fx/a8AYhFxn2k/mmbHOzmndif7GVT40US1rGkCecjoCsrrAtmgrPdHv5xuG2wgu\ndQybTqLd5FSS79k0x5lt6v7ToY6j1aYNKPiXO0AODW+ZsmQR3qiJHNOgIibKaPlo5KrxO/LgyE0e\nAylo+cwC0QJKwpWQ7Cvr1taG61w4GbcqOu84wvxsucGUdyNKT64ZUWHTvmuPyEnNvCaaoq9EkA2f\nWGp2107ez3X+6ngsJ1tE/JijqtyStSympB0BYl7ztDpfgLvfOvRzlI10fsj/b0JWiVJnNPaJDCJe\n1hB38mmJCjMrFNnpo00z5ZpOgEKPwNPHeYmsZfi8ej256w+W9E5yas1LMnEO0zFsood6rZJbzexT\nYa3NF8zSYL46OF8NWtgyg+HPGw0M3OdrDIl0fOb+gUHMoh1X7G9DhPhFw3GOlyGNCuS4oPkQ1+L4\nmuucGUCizVhnydmNjNykW8eYOeP647Jv2M7ct8zaJTSz4tpfVLMmpckAuuwjPhO15XrLtb9y11Aa\nlNbZOE5yiefhGfnEV+s0uCY7wy/GvFozo33DGsW5BPLtam5o8JTYXHCIlyUCghwiRIgQIUKECBEi\nhImbMQopSkkuZtKgMQXe9uKJqdynqsMAqhKsBIdlbjrBG3Dh39SSGZDVI/BW2+RZgj8KVNUpPIiI\nFFB9IIp9ARR1F4jU7GqJ+XhN283AayLanZ7p5/mK8rcaxx5lyoHKJgDskjHe1GluwjYu/Zt0eoF5\nAZeZfEj3moJxkfNoozJGEUnH+jmh2Yix9c6AMvOtmH1Lj/EGfUd5XLF5wy5bOgc5ecsztE/bTpqM\nmH44PiffzO8rX4v8TvLB51uG93YIG2ruA7S+wqcTqRqS0K75nhq3ENFNiN4uD662AU6eQyY5106N\nQ6+P6eveYjg7BLKB+YugLnJ5T9GS5jGsS8/8cYou7cNx/mFdnFwA9cH4KvgD+G7zFT1euq/XbAI7\n7PKuGmAkJ97wIt9VnnfzEzWxcegvLJnTkyH6bLh/mP8Y/NoFBPszWsgCkSosakw1jhdqWbv8obab\nfaqfaTu7+p7nC7ICP36qfWMWov+4iiAnj3fdPsOfqApGvu2/ExFpfYpzTQTqiecLEgXrPMa1cVA1\nESDKvtbzCH0BI4CIFfRUM8E+ZMdbK3DBb01eo8ii5LRQx/y1nhk0DvzupSyVZBxkLEJ8sRh/Re/1\nyrMF1+9kFUZME70nqaJyfgcc5KlBbbG8dXCvjb6ha3EHii5cp07f8PUg3edYN/EczWm7foznAq7z\ndNfXT9Dg6+zrsHwewbAI6O3s9rDahvhnYnxey9Alup7HWH/2v+2fE/0NPU6OjDMzwsdvsb5Bf28f\n+IwZVaKyC21v3tNVt3k0x2c9rr9rRWb3dRyj2zo//SWdW9YUjL+m89jartYfhHg5IiDIIUKECBEi\nRIgQIUKYuBEEOW8ncvT1gcwGVe5d+9AoReC/4uQYu8+t6j4L4xZM29xFC5W+gOHmaCMGUEOkWURk\nukQusH4+f13/Xq4rCpjhJXY6NNzgDvfVN+rmWVHpm++jHw8JUwS840Vbroso9/zbHLs3zqt8Lccj\nPgFiueFPCzVsE/ylMsFkGejwRI/b2/bvxRe39E16vA5d530g7zjs6p8BtZsbpOuCXGNUJwOZJJJL\nBJRIs4hItABaSUvSY1g0k88JHmna9vMWEeWlLTV4q5azVg/HvTvGiSIaDLSTSh+l0cR0XDtywfs4\nP4dGKFhEkpFR8tiGKsKwXzlOa0/bTY6AIhgualzTb073q+iLq8K2KG0N2Xf26+TO7Wo/yJMV8dXu\n83v6NyandqhzcnEfqO0DY7MMFHv0DUWpukDViyWgSBvK740fGZSWeqMbQFY2YQ/bVCSl+ZG2cX7H\nX6NdcszBFy6BfBfUJKdW9IZXlxjdxnFg514c6XnJ14EiPVfEWl6/6+fgiX5HPvRi65726Zmi2sVA\nz/HJG/6eW/9A7+kIVfzMhNDmffQ6FDF2vT52vKljn29CAQeV7Qmr/JHpKTKTF/iyajyfvd6T/PnN\nJOZC/OpHSk6tybZyncmhotLcx9oMJLcjes8sen59YE0ClSjaL1ArANQ2QYaxPfDrd3qKrCpUj6I5\nslKjWh2FDWRtOnjelORDY31za5rJfkVr4FJjbVkQpX12WGm6deo5/e1PNPPDe5A1SoPHMcbHTKTN\nfpn/PIhI9wnGwbUYGUGxNSTofuMc/T/GMwRrb/tT+AG0anUjIV6KCAhyiBAhQoQIESJEiBAmbgTq\nSM/nsv5HL6ToVvm/9i2SfFRXLUoeElUN8Jl8JRGRvKtvcY1n4EBRL5hvc3QeM4heiTc/ooorHyhC\nlIxQnXoBtK5l0GCE0xwGmkUuJfmqdh+HWvINmsdF9bBzhov9O0gBFNO9sfN45DpCB7e7Yir3nasa\n9qGLErhgjlNrNHNbqH4uofUcnwIN5jnYUbSsMKoPcR8cY3ApSzoisbKZ6OyBcUii696Jzhc5wdTN\njKmacOD7VlChgYgqK5mpdEB+rNFodu0Q1UYb5KTGl7VqZREpXlBvGceBriV5qqycTp8aZz3ylnH+\nqXgRb4GnzPN0Zq7rMa4ncp2hgEDUmxXcudVOxracc7oYFtBCTbeUI57veo1gVpLPvqlI7nQJDoqH\n6BMus7MveQWGPFP0dOnTcaXf0zcUmXLoyK0N3zfofZZwcDy7r8fZ+jO0AXT94hWDnAO1WiBLs3hN\nkeLDr+n1duen+v1sw/MfG29rZoL3VHRbx3xxV6/rwZ5+LqwmOO7Hk7d13lb/AucupQOYriXTZZOV\nAqo9h/OlQ++PgCJRTMPMQYnreraM+wXoVVZTcjn6xsDts/77T/Ufr1uGY4gQnx/pR3B7GxsVlXXN\n4rU/RKaP1zfW1/hY15LGE6OdjN8WL/T+Tfk8hQsp15rmY7N+U/sbiGp8hLV+Wl2L80vjVocsa3Jw\nXmkjR21CjHWutCpB0IDP+ax/pPdKST1+fN9/1yPK1IDOgDKXWGejL2lGifUhsXm2NPmco24zNe7x\nzEqggZ+bZ1hK7wFoz7OeYYF5S95UvfbiQdX1L8TLEQFBDhEiRIgQIUKECBHCRPgPcogQIUKECBEi\nRIgQJm6mmiQSKdPEyWORXhAZU4lioOkNR3GgvBckwcolpPhtMVOkKU4WFTnraqRAiw7NMkw6B1Jz\nlBGjXNl8WVOsrqzBpG5Z/JDf0tRz9BzpLqRdSF8o1nxKNaFsHKZwgRRuSoF2psyMted8GfI8c+13\ncoq0PAvUxkjx20I40gc+Q6g8X9Z5Tcx4im7V8ptW2QtYDCdPIamX+tNPu+Z6Sk56sHdGPypW00it\nJ6SE0CyFdA2KsF8YegHT1Dw2jTxIowClI+l7qkAE6k45qtIzElpPk57R8yl8QXEh6RmkMUTYhwUj\nhaFLuDQ70nmukJC0maQmFSfiRfYXNWmvmvFJsuLNbiiVxlQg5z6hgQj6THMTEZFkWfd/+Fs6b/N1\nPV7zBYxvlkE/app7oaH/nuHeW4teERGRF7+t7a73lcYw6/v35OWe/nb4dZ2n3t/Xwrj9CaQBZzrH\n//jv/0u3zw//6bdERGT7N/W3eV/HvvZruu/0r+/r77/hx/Pe9/57ERH53t/8T7TfWCsOvsPrWK1y\nJ0PftzZk9vb/np6P5tkKtgHVB813ftdTU/aPlR4zWQEdC80PHuvG+9/U9lcGm24fFgMffU33aZyg\nYGcPhZ5Y1o7+DZ8W7z3X/Xd+Q2T+pxIixBcL2jy3/ZrN5130DBQLrB0FCkyTY1jTW2oZ1tr0FaUg\ncM2PQTMgJS+CvbRujAud1Dusd85+Getcsuopf+5ZTDoDJB6dZTYLtJd9QW60BxtqWD07+hmeG6Rk\nlob6kINKkZKahnWW0quUURXzDGOhN/+6/33QxATjS+54iUrKTJJWR4pcehtyk0sd9L1aABji5YiA\nIIcIESJEiBAhQoQIYeJmEOQ4lrLZkKJds+jtGCSTb4ko/ikaQEu3lvEZRQVNj87Rmjk7gqQVLSvb\nNckVg56WtFXGf/0n60COz6sIH6WiRETy1/SNMoZkTIw3W76Fy8aqGyejWKlKgfEt1RXiYezuTVfE\nWUpTmN0FChJoQVyRj+KbP+XCiJ738T3tqo1BhABBpuA8pXBog81iJot6EjmmxaZDjPm2T8kxMwds\nJ0cRRjJQhI+GCjELF9teAo/W1ZwvIsosyotoPW76Fp3A8KJbldLLj9FnFt4dGkF7ogZENFB0WGAb\n/p6seqSDxRzODjuuFmU5a9SxR254zpgtcSiGs2vFcU98AQr7ywI+FjU6NAYFLoUpjmHB4K0/1SI9\nJ4J/ot9frus1lE591qaMUMh3oH3KPlY5t9sdRZJbjyF5Zy3Hn+o2a2Pd5vmK3hsb78E++kD79D++\n/Vtuny+99xPtW/amNod7+2Bf9x385ft63PI1t8873/0PRETk3o8wL7i+GxeK4g++r4U83Q2PXiUH\nin5t9BRd6j7SLEEX/S86ei6eD33B3St/rsWZlJYqYTyQbeu+Ua7I1+CvdvwcQJawCfOVxomelwwm\nN872duavndYjRaLWf7Qpe752KkSIzw8+N859li1+rn8p2VYCRY1h9CNYT20GkJKXi8d63ySbeg9w\nbeYazAyaiEhBMyauVXy2MKPJtXjqJThjSjou+4yYiC8OJNLKdcSOsYRZD58x+fPtyu8JDJJERNKn\net+WLMBnX1Aw6xBsm51k3/g8Rcax4LOEJkGPnvjxdIHWQwaSz0GuvSnmZmGMq0K8PBEQ5BAhQoQI\nESJEiBAhTNwMgjydiTx+Lmmrxn0dXZWhcTJL5HEC2eP/1CNjjtDEv4u9AzRYVrYhVuYQP/GoJRGp\n7jkQKMql0bzC8DsjcrCAEBZ8YyaqijfSODLvE5SxIWeW8nVEevGZXFcRkQY4WJTRIUpKtJGya/HI\nIof6XYExEnGNj5qV4xO1FRGJae6B8+Hk0Dhv62uVtkVEZBWIAOXVMCeU0KPsDm2LRQyPHNJwclcR\nwxQ8NydFZw0vyCPmvJC3TAScSKxFack1RnsxRO8dEttpV/at7E+EBohAgrETNSkNR9xZokIon6Ym\ns1d1nwRi/s4wRAzXj2jFus4j0U6ikYlFe3itgFuY9HGOcb05y+7H/nrLeU5hCDDFdZBA7qgN8Jx8\nXBGRWV+PM/wZ+kseNnn6QKYKg9JG5H7zXgOAQ+SYCE5ivAQ8fxwmNmt6vnOeFpq2GGW46ZQcdCDu\nvWp2gDUJsTUtwFznDVwzO5CAQvsJsimNM89Fd3URXHdgzEBeefMYFuEmO8FsjMu4XGlL537eMXJy\nMKBpHa5JvKiax4QI8VlRvqJc+9gYJc3uwcBnojdfjswsr8e8qddf06QqihbqQXDfzr6qWZbGc72f\nc9jazzp+LW4cYe3DfSNEZ8c0gNLjWLnWYhO8/1W9Xxr7kKY81PbLARBZk2mMsF4zU+U4yBg75Vsn\nd/xavOggQ3aMrBrqdY7fQVZnpM+EznO7fsOY6EiPN3pNt6Xd9mIJ2WTzPHL38l3NEicjrMnP9Zk2\n+rZm0ro/ub4GKMSvdgQEOUSIECFChAgRIkQIEzeDQRDQDgAAIABJREFUIDcbIm/ck3m/ar7hOHsi\nUoAbTJSJb3vk0PJz3jIcZPAsuw/JwwXS2qmajkQG6clbeNsG2je+q2+06Uj3zc70TT1v+7dIorwR\nUNp0R9EgVuyWQNxyMz5aapJjXDRx3EtwaYlQGj7xYgA0cQwUi2LnMyhuUHR90/O7aIlLy+LS2QWD\nM4X2sx1vobxY17frBTjIjSNFNxcYc/zjD7QtYzUdn1cVQuo8ZcePnnsDD759E52NHyt5jsLy0SGO\nZ9C5nAhyDYEvrXqJiEjhP0c1tQdWWxfgF/P3K23YdpCpWLzYqRw/sWYp8yqiz78NfgbKY4XzOS/O\nyAXzmBOtpWC/3SdrVI7H9jjX8QPlEeaWX4fjLDpAdQBSEmkZbUJY/9Kjl60T/ff4HtAWIPs5eLhE\nz6OxnwOX9dlURIXKENNNRWEaB/r7omd4/8yI4H5sHehcnN8Fnx3np0g9N7jfBTLs+ILI8CSKeEW8\nF26vun2SPb3GaTGf30N7XEOAjlmjEK4vjHkfcz/S+2e8rvs0n3ikukD9QN4mSo85z6vKJKn1p0Gd\nwuVm6uzgQ4T4uYE1szAZswbVHJB1Slm/g+xexkzt3N+3CTOJqMtoaFmA5Mcw8EC9Q2vg1YGI5HKd\nIzfYGkiJ1OpB0LfmEGZUWIMX4BfHh60r+9TbcWZXHz7Qv3j+tia3/bZE1JllpfEX+wpUmopAIiIp\nMllcj7rHZ5VxMmu8OPbmIuRMp8zUoj1mkTs/0Ht5ceSfryFenggIcogQIUKECBEiRIgQJm4EQS7S\nWGYrbclbrPrH95l/W02BrE5XYH8MLuXlpiI4RL4WbcMjRXMdoLTzFShggCuVjvE2aSh/8wGQ4SVF\nikYb+la8/BFQRyDVs6FHkM/v6Her7+vb8Ogrqmmanes+4y28fR949HSyUUXLm0f62+QW7CzBE2uc\nGpQWSLdDwoF201I7BkJtlTzm4E2Ra1oA/XMcrUNwOA2viqj1bIjTG+m8pef6ljz/za/r+M487y3H\nvPD8JOC/NQ4nmAPwf3ODHOJUdd5TVHbyls5bc+eiMr6Le54T2toHvxP61ET803PfFxGR+Njz3ji2\nyy+BJzbVeWw+1bd6WhynJx6F4bHjC8xPVlNYASpz8o7n33a3ddsFshjxXLe5uKvXEm2dszN/TucD\nbTcZgx+IeyAbLSptdT7yltazO3rMyzW0+wK8+F0dz+wV5Tynp4aH/VRVEnq/r+i/ULkDCE4XfObS\n8NedDjXQ7RwoSPuPqshRYarUoxSV8+9+KCIi96ZQnoClK23F3/ifvuH2Id87+fN3RcTrqN55ruMk\nitX8l++6fdpL39Tf3vu+2BigUn8BfnR04NU/Fujn2u8BscY5pDIJdaRfPbnn9snf+0j7hHElRPSB\nGC3tax8XsCK30XsC23AcN68ha2snvuqeFrXr/2IqH59XtwsR4rPi4N/Xtbh96LNfC2QuRrewllzo\ndd7d1m3O7iPrYrnuWIs3/0Tv071f1+t66VO9Fvm8OPyqXwf7T5ExHWs78y4yQEfVTFz7hc8E58jS\n7HwXmVk8t1fe1zXg5BVdczp7/lnJYzeguMNno+s6kjyP/45Xllr6RP/OeqgdmGK9flu/7z5XffPW\noZ+DySos4TFfC9QINE84Pt1u4wf+2XL8Zc2MXdzVPg0/0bH3H+g2h+8sXRlPiJcnAoIcIkSIECFC\nhAgRIoSJG3TSi9ybr2t8ZN6Ku5nbVkQkb6PidAJ+FamviUeQF6CuUs+XVfBFBkSZFfUzo08MhJXo\nX4kRToDWZehT3vTHaZ7hDbOjGzdO9a3boZsjaEx2PbLr2gfvkkii4G04BaJo+YgzoNrZOTiNpOGC\ngxVfAOEd+DfphCg5UGcKNZSRHm82BLo99m+48x6Q6UZVO3K2rNt2/lo5rqVxYuIMZsvglkHBgZzU\n7g70M6/TQSYvjRrANb3L/qHnkZaneHsHekllDec8iMinVURZRKSLPnHf/FjRTFdBbdBTcu6cqxJ0\nLp2WMbYbGh627Os4GtiXSg7NbbjvoZrbqn80qPFc4z9Tv7NB5QXjEtXAWBvPgfDCqZFjzoCeWh5f\nybn+hmoNk/tOTe2LOzq+9p5Bg3HNEPVpvAvE9a5yd+NzKHscen4dEeL0jvIBj7+j2/YfKdKSPtXx\nPvuezwrc+oH+jV+7h+Nqn86/qkh45yF0R9+87/bZ/i29Jt/+Cz0Oz8viK1o1nvxYEezo1btuH9lV\nFH76tqp8pLhfEmqYQoN877uew795qP2nAgrVMhK4co7fBBL1fTNvUE1hZXt6Ak49OI1Ermeve/e9\nbFfbPfvamuQnNZ32ECE+I9b/WDND0flV8ewlKEbE59CkRyam+zHW08SsxaifKR8/ExGRTe6DtaWJ\ntbjz1Gc9YirtsH6Ca+ZFtS+FVUjC39vHr1SPCyWjlWdw/TOc3Vavuj43qEp0Wr2f7s3ecPs0Hum9\nXrJ+Bdssf6L7ZnvIMF2YrCHdeOdV/nNEt1M+azBHIiIrp7r+DD9EhvTpXmUO1vbxPJwFBPlljIAg\nhwgRIkSIECFChAhhIvwHOUSIECFChAgRIkQIEzdCsYjyUtKLqymI5NJ/x0K6KM8q20SgLdCQIDKZ\n6mSOYrxTTX86aTgaHUDCiTJplXZRwJBd6D6tIxSHQWKtjHyRXbkEasXZvNIuU7gSQRpq6jtXguZR\nOqML2nVG1e9nXmYqReFbMsK8OL4ExoNxpOd+3mJaSeM30jGyESSoMB6m4UREGpBzK1PM30V1XEw3\nR8ZYg5JCdXOPGGm8coiCy7wqmyUiEoHqINgmgrQarVIplyciEtMWvGZIQrk3Z6Jh7MOdLBBSaNw3\nBkUk6vn23T5Z9TqjzJvbFu3nw47bJKXMGwseaTMKkf0U9BJamIqYFCDHQ9mycbV4MjrzhSFCi+kB\n0nq02aYM0hLm2hynONN0ZHp4UWk3Bu2kjfOUnnmqijP1gFQgqS/JMeTyUFhmTVk4L7Shbe9r39K9\nqmRSe8/YU5MKQvoM5p4Fqvw9MYYD7d2VynEEad4U0pC0h41OvMVrgfnITiB9SLtZ9Inz2Nvp+X0w\nRko4xtN5ZS6ae6BnWDtd9CmFyQvT39YOWKRWWAr6RXund8VgJESIz4p8WdeWxJocwfRjtqbXZgJZ\n0xT3+HyLa/FVQ5pst4ltlOqQ0eippW1MtkzBNJ87ExTPdVCgnXgqoYhIbMyuaKo1RR9oZkJaWDHs\nXdmHZknOPIRrJOh8vDdt4XsyQYEvnmV8dl3cAU0Qc5EdezrTfBkF7XgmFiiQTmvSrtmBX/OLga6F\nk3X92xmhT1hL8i3thzWHCvHyRECQQ4QIESJEiBAhQoQwcSMIct6K5fTNjkyXqgL57QPfPIvwFq2o\n8plFbJR0W/iXO1l08BZaDqrbQAqOaHMy82+rswGRW/189jq/h80k6g2mQ9/XHC+hMxTwtI71bZVW\nsr7YzQyOXcN3vuCu+ruVoGPRYeO8WdkmxjiaJ/qPyw0/byxipLQZ+zIdokhrpm31TGHfxS19U56s\n6bbtfSCwGPL6H0Jc3aC0RNSEb/sXsN0GahYTxW3549CGmogo96EBSUFk9NIgvDWbbYcq0NCD82dQ\nDKJ7zqY6rqL3tCq1hRSUOGM7EZDesib4ziI3EZESaKWzRsZxKB/nLFdtQV5aRVucrWpEq3Gg9qa4\nkWYvLKIrMT5aZ7tCRmvRvaaFOdPbQDhogDHUcZ7f17+DT31fkpHO9cWXFQXp4bwsVlDMsgwU6Mm2\n7z+uiXgdxhcbyEYkWnDXxngoQSUisgyxfWdXDpOPBQtxMa583RfPjTeLynFYgDRfRzHgY8ix3fPm\nIkSlaEi02ERh4jMd+3yo5/j0VT9vXRoaIDMyZzYAdtSj13Vt6T1puX1kQ8c6v6W/pS1mU3Cucf7n\n1mzoNbVZP3ujLfkHAXcI8cXCmVyZtTje1zUq6es1yayRYO1KgeIWPbMWI4PJdc/tQ2OnCQuAvfRq\ndIl1B+sCs4VSK3KzxYB8HmQwn2KxsFvvuKYZ62yhjTy2yZFRjF946UsRkfTSZ16SbS1qjrBm8Did\nXR1Pc+f8Sl/TrJqFbMCKm5m0lIh77NdsSqIyu8vMn3RQzLujRY5EwUO8XBFW8hAhQoQIESJEiBAh\nTNwIgpyMc1l+90wWdavpIy+7xTc19zepooB8y6tYTcNWt/cAPETyI4HoOF7z3CN6eRd8YRhRtE4V\nOaKRB3nFC/P2XaQUGNdtkiO8eYKT5eykjW00ucGFe4PG93VEwHDLKHWXkoNMfjElz850vpoHA38c\nyrfVOK6LpTb2BV9633M1G8e6P2XlGse08cWcw07TvuXTypg80rpVKO07xfBViXnkaI/ctaJms0xk\nWUSkoBQbUViMq6jJulkpNcrFUXqO9qM5eG8xpYbMeGiJ7VBsShUVVd4e5b5EzLXo+ohzSQSFltNG\nHs9ts6jxlylbh8+FsY0m35DScwXao91sMrwqlURr7OhNlRZb9MCnA1+dRjvzvkc1+W+aswjk3EpY\nkad7yCQ0/L1QzvEdkGJmfBrH1fNTGCUzd66I7AP1mazqeWtH1XtcRKTo4fzTOpaoGOsMmJU4N/J/\nyDLMlnRcnUe45nFtJudE7b21uZMlBGrPegVek+klELXMoHF1SSfew/yLbMpsxe/TfVflurI7HZ9F\nChHi50Syo0Y4VqKyhGVyuqv3YkTePH6PkUmLT6/yYhe7KlOWsv4Da3MEOUpy/EVEBFkbt9ZjzXKy\nbrh37NoVIxvkal5w7+X7arQTY921a2REox0+FyjvxmcA1prWthkPju0Mo5AlLLL1ymc58/ukXIuZ\npazVEHBNWRx6yc0Ea34ypPScHi9nHcJtzQyVL3YlxMsXAUEOESJEiBAhQoQIEcLEzRiFIKKyVlVr\n0FMqT5QEuEoaeeD/6OT0WhozQViqLyT2R3Fvnu6vadd9rCO711T+0lyEfSRK6xDrjOoZpnKffeEf\nIJOu/0AdHVfU9MEh3uwrN6mpWmh7QMXqKBZ3ya+ZA/w7qp8ObEs0wSlHiDikMwL3yr2hc1+qNVyn\nYoG3bbYb0ZwDyKRTxhDDWybnGGhc/U2tMDxfthOxHapYAHF1fGPbJ8x/TASxVpnNObq2b+QV43Pe\nRzU5znHlDADtcQg/EWSeJyA5tHC2+zg1ESCw5ALyHETWKARjpaJLBHWUBEoKDdiTp0Y5hog4ucjk\nOtPC2pmzWPQe54VC+a0TcIUvaByj+zaPzDWKc5WQg445aJ5ijjGO+MyjStlhH+0BOcM22SmOw3Ns\nlTxosHJKFRP0n2omuDZbx57rzHmLnKpMVjludgK1kUnVqEbEz7UzarBqH1K1HOdcNk/mFTv2ECE+\nL6gOFNkaBSCfxVC5utEE9w9+z4c0xDBrNBOZe8jE0DSjtkaSgy8ikpG/SyMNHDeuPWMcj1n8Gk/1\njXiMjC3VYvo9qQcVhWLWjGQ1Ix2sOdNVvxY3yWXOqvUazNpEOdZk86zMoUjBPhVQ/+B4CmSE432T\n6e7rOKhUlGFN4bOlxNofTYN9/MsYAUEOESJEiBAhQoQIEcLEjSLIV8KiufW3Un7tkFcgpdeAL2Ud\nNeU2n4GqXrdt+dmbXOUMOjSWyDI+x6aR4irHuNK3a1Ak9sGPtbZN/bPdpv7XbXDNwOrfOWUIcEGp\n+mAQSiKuDjnmb0Ry69+b45Sci/o+5JeaSuOSyDG/Yxt1q2bLFc6r+7DfJRHx+nHF8/XYblRH53mO\nbcV2jRNHe2eH1OTXzFutT0SC3Gd3XHOR8Tfuy3br7dfmRMRw+JH14GdmQYq5QcqZnEGWxnG5sY9T\nJrHH4bWZ1u3KuQ+ss5tXr7uSmRdu0+D9WdU/1f3LynFoN1s09LPThTX7MAvAsTo1ELaRVfts93F9\nIy8e+5DznJhK/QjtFllt31oWgpb3OsQYx44/d60JEcKG4xdbBR5e1+TL8zcguU73f37NWsz1blar\nXWGmbmL24fpDq2nWqMyrHPwyv2btou4/0efammafE2XEdrEN7yOu8cxAXdM39/yj0saU3ge1cYpI\nNKUcFcbDdY/bkFNt1ruY7fLY5FDz2XLNeEK8PBEQ5BAhQoQIESJEiBAhTNwIglw0E7m435NZr/r/\n7day0QnlC2e/yjme9cEN5Itax+gTgyqUjvv4rL8tWnCRm1U1gkVEpsOqM9/Zfd12kKEyeAJHoWWP\nBk2Xtd3+U/BW56YKXkSmA2ol+uM4ZA2oMn+jIgY1m9OpR0ILILiNC/Aga0hvNuqgP3beMEa2D9Rq\nuhSjLfAujcLGeEvHOl7TbVpDoHKYr85MtWfJK9WGoVqwobqxyQW4rvx5FVW+qUHN2DdwaMsV3ddx\n2IAULLY8JzQh15noBXSVHZ+UPN9LX9XN74o1bZ8oMFHGEs5z8al3aiO/lxxWx/elogbamN5Zcvs0\nWSkNhztuMwM3roHzx2poEZEcWqWOJ093qoVy2ohCxgaVKW9rJfYC+2YYRwJuHtUtorbnVpMTLCf6\nN4bAhVMxgQ524/mx24fITL6h80+liIjKHURUUOlug1Xo3eeoPCfCi370XljUGdcEquKJ4PSauM7n\n4Fgf+eP0HkH/eFKtnM9Qub8YYZxzwycGt735FGoc4BRSeSVa6PHaRwa9IjeSCBc4kjxPCVRiclMN\nTzWWGHPNSnm2xXul+cRXw5NXnk5ylxULEeLnxeWXVHO7eeT1iXl9XdzXa7UFBaYGEN7xPV2L+awR\n8ZnYLtZRrmsNrpFApc/f9BzhbgfcYDrpQdkpPcE2vEc6xpwA341eoWuq/qVSzWxLj5vt+rUrB783\nQe3DAu6lKdSi2Obx2/44K1hPp6vV+pLRLWSL8BxKjRrVdI0KVliDmfhd0+PnTd2na9SOLt9WVaDJ\nira7RPdR3M/5Muaib+YgxEsTAUEOESJEiBAhQoQIEcJE+A9yiBAhQoQIESJEiBAmbsgoZCGDD06c\nSYf7/nR8ZdtOG9JflF5po2gGKaK8ZQp5YBrS/uQADaJopol98iqBX0Sk1UXKG+nlxrmmgFq7mlqP\nLzXd2+771M2ij/T0LgTFSepHHztI5UZWSq1mfmDl3OzvVoqnwNjYB1ekwLQ80mONgbFmXlSLEVgw\n1IZ9pzM+OPSmEumZpqXbexCHh1WyOw7skK1sFWWAkiOkpPNaodoI8jfXFIZQVD1h+prSXRCVT449\nXSJiupop7wnS8JOaEcWFF7SPke6KLiBZNNH5K86QWqdkoJUrgyyPMyBheyzGwtxn+5bKgQKQU2yL\nsWYoHIsmNB3x+8QsipnUxOmxDekY+bkR298lZQdSZ7T1puFKBzJwx56SkMMKPAY9I+9pu+7csuZw\n01NGmIbMDvTYzjZ8fUU32FOTgrjv07v5Ca4jUGGYtsx2YDiA62Sy7N+tezQx6el1W6L/l6/q587P\nrsr9jTdx7ZPOgD44+agu7gEr94drnxbQjQdqiuAIDdh20TY0IErmgbbijENqZiDJ4Ko8VYm1KqZH\nfK1ocnZ32f278dNH+o/bQwkR4otG+xnWsDO/3lFarPsc6928WqTcgDShM5EScVb2+Z7aN6eko51A\nghPXf2fHy5Wl+zg2JRUvQMHi+sZn9JGnbZGi1DxCH2C8Jfu6lpAcaNfIlDQ30LbSfRTPQf6Nz5j+\nE3/v0IK7tT+ujDVvD9Em1mZjfELzLkpfLpZou63bFFgzrQFT+4GuKdkFqIWHOifFthqDRLDFjrYP\nJMTLFwFBDhEiRIgQIUKECBHCxM3IvOWFRKcXksxrhg2maMqZPQApJBKanAL9o7FD06PQCYoIojH2\noeEAi6RYDGZMLZJF9W27hUIhvoESpU2MdA2RbofS8q0b6BMNEMT0zSFQlMahfBRke5yMmBGAj0sU\nXwFtlJqEDG2YrVA7kVUWOlGuJ+G+lBUzRgcR3thTIsa0JEX/S1iHVqSF8DYv3DatSlq5czAyVqWU\n1yISTotPosPXWE27flLej5JtNdS+IouGQsh6HygbJJdXMxXlrHYcoOVxD0gh7b1P/DXqzmXNQCO+\noKHHvDoGEW8xTRtVZhacAQal44yxBo1V+MWU1zfmANcmjTFsjO8o0spi1HZH53i6jHNhzHQWKGpd\nBgLFYpvJHUVg25zPti86jClnBJT59L6223kGZBfX0Pnrvk8bmNP5bUVUaXF+8rru2xsqOjO74xGi\n7MuwiV4FCou5H72ibQ0OUcTX9QWzlKU7va/rzNpz3I/IuFAi7vyuv3YHm1oENR9gbaJ6HO6NyQaQ\ntbNVPyCcQ851do5iyqPqunP6mp+3jY9RGLvZrMi/hQjxecHMX2VNwf2Y7sGSOatmWZMzrDXHZ34f\n3Jc51zVk/NxzqqXfM5skIs6C2WUJuX4zmxdfleDks8k9M7F+FjSHwufSrN9uPUU7BfqUrGA9wHrX\n3DHPFqxjMbPQlzQoQsEfsrDMKoqYZyLGlSTIlOF5nsz1Xi+sjB2yaPyPEFFu9wxj8fX5VVvvEL/6\nEVbyECFChAgRIkSIECFM3AiCXGaJ5OtDJxPDyKwxQIMmApCWqqEsRJDztkd/Fh3KsijiRc5x3s4q\n+1qeb057SXBzL+8oAtU8BvKKfW1fvSUv3mzRlwJ8ZvK7yqbvG4/JfjsEnCLuVa+RyjGTEdD0RdWI\nIgaKm695HmkMtNkJymNOF0vgVpLKafjR+ZrO13ygSESjUTNFOFB5KosM8M2Z3NMSwumO19upSt/p\ngWhzjbkg2j2r2XKm/jpwqC+PTV75vCrEbs04yEcmgujRZ2QF8vRqGzX0g1bPDh0pa5xxESkp9UVD\nGErOce6JLljkvSbV5+bAyb3RSMTs06hKBrn5Ipea6LPpI8X1KWnYOI8qnxmNM39O6ZdR4J5LKEk4\nxja4rqNzj/AXRNox5mxUtYQnip9cXs1yJLC5bkHEv7WJ8wLEPzE22GOgstEcc34JTuFIr32H2HSM\n1B2O0zrF9YZMkqsZwHUeG4DIZYzQ/5LrEM8P/X7ODXoFzjvnNqlln9xmx4aTzLUumISE+AWC64Rd\nuyJmXll7QQ4v1oVoyUjCMeqGRdgnh1xmzLXEPJPdusN9ufZPq/Ugdj1nnYTL4pbVTKBb76wtO9f4\nWgaY0pWcg9iYYEWHJrNnIsUzmrb1lToa1pew/ocW8XzWYJ0ozPiSbk2+DWg390mA0hfF1edFiF/9\nCAhyiBAhQoQIESJEiBAmbghBjmVyqyOzfpW32mr6/3+TG5mjwpyobcUWVkTmbcOhxL+zM1THozmi\nzESU45l/u5sPgCJBLPz8LtBTiKqn4GzOlgxS3dLf2of6WwPKGotWzdr2mtcJp2KRU5y8WfndmgbQ\n4CRDuw69wr4Z0O/JmkfNkinRrLzSl+kww/eo9jUqGpMNRXsnK7QF5pu1/ukOYKwxNqefaCl+c2/S\nRAagXiDGkpf7xHiLjxyiB8SB/Ou+V+WIarbUNK8oazzi4hpb76gNFBt9iWvmD2J4YuSPO24wFRaM\nOoaISLlk1AvAA3TH4eGBYsY1lNsex3HO2VdyuIF6W+OTeFm5d1R7cFXk3IDZCKMuQcQ9O9e5TS+r\nKinJTK+H1r7houO3xRKuyRgo9HkVCS3PjMEK0RbMW+uoOi5yAVvGI8OhLWcYI+apu6ZzQ36iPW6y\ng3nHb8wSNI6VN1gAzY9XvVIEeZqtPaD0VIUBx50IWHZh+N5U7sDnoo/zRRME3ldWZQTnjHPt0KoR\n1WB0Tto7fjw8djItg1FIiC8ea3p9xw2TfcW16UybyMOlqQ7VYIZm7aICD+5lcvfjCdZe3Pv5ml9T\nUmYAiSCD+xyntf8W2CwZDYOg7iA0ZAJ/WVZhSnRodl+iWg9UovCMcbUYuF+mW348LdxrzrQJXZ0t\nax+byHDFuVHggQIOTZqEz2TcmwXUr+JTf5zy1oZuCsWLDBlbZttYixOvrkiIly8CghwiRIgQIUKE\nCBEihIkbQZAXrUiOvpLJdLmKnHReeDR1QfdKvJjlACRjvHjmbbw1G/AuXwJnCHq63Hber7aVGMrr\nAi+cCcCdizf07Xh0R98EGycJ2vB9Tcba0MUd2E0+REX9FriboCxNzUtkCiCyyKrj4ffsU26EPTg/\n2VlS2Ybj6uxpY+ev+veWxgmRrurxxuu0tNa2+uAd6zhg+7mk+7bRLuf2/g9qHGERKaCzmwDRpcZw\nUdMnjnseDSY3LVqC9SkQAacRzcrmU1MBPK1ydOvh+GjG3pToIhEHx83DdUE0WixPDLw3ZwtNFJtI\nIXlqRn90AX3MZAnt0BZ7Z7/SD8kMB54cZ/SlONY2HLKMOYiNbTQRYnJaCyLhnMdDhWfjZYOe3lNL\n1N1fh8Xrojp/Z2/q5+EHBoU50XEcf0nnYit9Rbd9FdrG4BcPHvh90h3VPB29c1uP92va1849Pe7q\nUMd5+dv+nKb/7J6IiJx+W/vY2dExH7yj8/TKB3dEROTwO14p4jd+510REXnyh1/Wvu4oCrz3He3L\n1rHuc/Rr626f4Yd6TRx8Q/8ye9Pd1XM7GWpfD/+WJyEvPdIx0779cg3qH4eKzh1+XT+/enjP7XPx\nqp6Hs1egOX4APec9oGOY+5M3/TlNp9qn/W9HMvtxICKH+GJBTr+N4kDh14TqMtAYLoCquqeDya44\nfvw61F/2keJhLQbqANJdr63usnZcw8gn5trMDOHQ18S49W1H++T0xbneEY229S1AYZmZW2zo/ZVQ\nXxlW9Y19vxbnz3d0m7mq0DDb1v4I2udYq8um/z8G63CcKs+OahcTwSYvW8wzrMAaQj15pyaypg/7\n/PFzbfvebQnx8kVAkEOECBEiRIgQIUKEMHEjCHJ2nsvtPzi9omKRnhiuI13XqEDBCvtmlbdM3q9u\nq/9/732Et2G87ZFLRO5SRcUCbjn8bvSpvuG2d/UNkRXpi75Btzt6zOYBKt5HiowO30sqfY6uQT3J\npXa8Q/7l94YbTJdAqmW49sgfQ9Xt4BOP6HFujI5iAAAgAElEQVQcdHETp2IBXiwUA5J9jwwsr0N3\nFmhf4xjngagplTfmHkl2aCUQ15gILFAGcngtSusQgRf6tp/eUgSRKEMMHlxkOMjUx2S1s9NSXlT5\nvUS0RUQi8niXgWSAs+sqtMlBTsy1RA41+dBXdJaBlvR8yiLdXK+2Q93OLUVlYnBsS6PrHFFlgTzi\nDSAeQCsiKKHku/tunziDignmheMjcpysrWIOPEpbvqdoy2amiGvRAuf1QhGo4afaVnph3bV0rL0H\nuN4+eiQiImu7ipbGB9pmOfXXweJYv+tAK3Sz+5qIiAzeh/sU9un80Zt+n4c/FRER4kxUWln+GNqs\nz16IiMjKD/z68Gd//DUREfnSDz9BI3r+N6g28UKdrFb/2KiZQH1lpatz0HgONAvo2QDIUXa56fbJ\n3nus24Ir2UNWQI70fmnvKDIUPXrh9unu6nHaL/R6IAdZTqqV9cP4rvt346Nt3WfvjuyfBg5yiC8W\nDl01NRgx1tGcbqmZfk6QiSugcmSfeyW1wD96qPu8+ar+ABQ1RnYqN5nGZL/mRMt7o+YymR94QnEM\nxLa8peucjKGdjPUtBvJq1TKog0/EOqHyBNdZPDMXy34tzl7XzE9BDWj06fJtnYvmvqLCybFHnclX\njtinV2/pZ67bUH4qHzz246HTKeYlwfjyp7oexK/pWlkeejfBEC9PBAQ5RIgQIUKECBEiRAgT4T/I\nIUKECBEiRIgQIUKYuBmraYlE4lhKpq9Zo2Itkz/jN6aBhVlJ81/2sl7rwjbq+5jgPhGLEz7rFcAq\n1yTVdvm5rB2v4i3BLtT7klTHWTeSuL4vPG5V6Lzyb2dIEl3d5rrPpt9Obo2UDsr4GEqCo10w5VdW\nqSLOerq4epyofhy2S4F4Y1tNOkHpPnPbmnFMZD5faRc0jdpxrK13/bu6iLwT6K/MAaXZqrQfmmTw\n/ET2d7cP56u2Df8a2Tr+VtbHHlXHGZm+ufki5YZ9ocnMvKj81f5SghCpWJpjsJCG59gU1LigqP+c\nsnx5ZdtkZm6+ejsYK6UWnRW5tawlq6OotiukJJHKY2zknT04aEURZKqcFGGeVftsxuHa4VzjuDGt\nZE3fOF9urmsmDG47O9ekSS3K4BUS4osHqQim8JfrAo2pnBU0v8+q65P+WKPPwRCH6y3XfJpFiYjE\npC9wLeTn2vpn1yG3prMPC+yDfdkGZeXssd26xmdAbd3IDd0y+4yx5k3QLGkKZKgcHFu8qI6VfeM+\nlXU1q26bZLVt+DzMquZkIV6OCAhyiBAhQoQIESJEiBAmbsYoJI1kutqS2aCGvBlUkwYXRRZV/hLx\nJdpVMQqBgkzzBEVeBLM6VZTTIkbzbtWS93IdfYogBH6ub4K2r6X7p27TPNA+LPoQGGdxoDE1iSH1\nRAMSwkauLwSXDJw078IoZJRV2qBsVAb0cbJuCsdgCxzD0IBo5nQFhYO5Fj61TQHhZBNGIUO8hTtk\nXH/vPNQChNJIuNFQg29MlLu5Ii1kkYGaXXOJwrq65XRiRPAL2igTsUvnlW0dsmtlgmgpTUOLmj1r\nxII8a2+KAkK3DcXisS37npiCOydhZCXZRCQ5usD4UCRjitqiom6kURsfit2slWw5r1oXF3WTFNi5\nijmnlL2brsHwBNddAVObi9s6x90dc43CQGd2WwtaOocqUzZf06LGlOjI4YkfzyXtbLVoZQyzmcYt\n/dxkscymP84aJe5gHhBNdaw0Dmpz7pd98elssyptRxvd+bLOfQOITbE+9H3DsWdLuJ4i/S091s8L\nFOiObvlrdDjQYxYoiMxRnJviXhtv6XXSfWjOOYpBZ5jrjDbfNfmrRc+jSsm6FieNbjckzwKGHOKL\nBWUmS2MkJJTcdJbJug1lNBOuNQY9dSgsDXD2tKiMxc5sPzXW7Sw6ZbE2zaDcGo2waxdlP9P96hrF\n79nX0hRZS4k1CxKflN4sT3xhuYhI49Csg7taXFi3gu48R6E7jl8a+/ckr2aWYtrHI3uUoI+5KUKM\n8W8n88Y+cV1HP8rrsmwhfuUjIMghQoQIESJEiBAhQpi4EQQ5nhfSenEu2VnVZplvZSLiOFKFk3mD\n7Fuzaru8aHv0p4BFcvMZ3urAr8qaQE/JzTJyN40uzSPALUz07ZUWvPGFvi03lvyb9KILi+l9oKWX\neEuGoYfrs5V5c5xq6tVV0VS3mZF5a9Lq8vJ6mTciim3LhyQPEtaa5EwlE0iozcAVPfBv420cM7vQ\nMabHVYQyIqJrj0MraZpwAMGj7aizc7Z2yxw73rojWCPzDZ6obdnzKIBDXGsyb46aDrS7KHyfo0ar\n2ge89UdEOoBgWhk+xzl2knaYJ4yPiEBpEJV4BVJ35AsDechh6RrTAtqgzpwvJ43URLaDqDCMV6JT\ng6iAa1y28Bv7NFOEiFbUznhFRHJaMR9pu3lX901O9Zrpom/JxCDV+K71DKYvkJFLh3Da2dPPllvr\n5gXoS+tUz1djW/tCibvWobFzZqYAMoUcVzqtcoTjUz9v6aHOqbO5xjWTndERByiQua4LoGDZpbaX\nPYf8I1Gtsc5jZ9fICuIaiYnGEf2H0UB7B9emlbY61mM2INEXXdBquoqsWYv7aFelsLovOpJYDnSI\nEJ8Tzm7ePD9oE10MsMZD0jHGekpJsmhqUE1CXS+A6CLzEjFbhYzafMXfGxnX8jkQXdy3ddSsmBvE\nFRkZ9iEeARXGM8UZJBm7dcdpboDLzz4he8Tn0Hzg//+QbanEoqujwHNuvKX3awuZ1OTIyLz1IX16\nqfd40cPnE6DaHTwn9o0PNjJJLrPEjNYEspzoB5HkEC9XBAQ5RIgQIUKECBEiRAgTN4IgF2kss/Wu\nzJaqzRnXaJkP8IZJ/h5MQNKRvj0uevqWuWj6/7PP+qiGnyonkHzceQ9VsOBhWg5yDq4zt6W17Awo\nZvMEQuBtf5z0Ut/ex3f07br7UN9Wp5v6tkxUbrLu33AbZ/pdkWk75D7ze3KG846fk8mK/jsbgf86\n5V/dNtvX8Uy3PFczOyFvC6iv4yBjHC2d5Y6p9iUHmX1qAUmcg3fd/tnHumFhEIhIEcIoBerrlA+A\nBtf4YvpTFSlbPN++2q6IRGfG8GJes7muGXdc+V48B7l8+rx6XB4H3LZrEX4qN5AnO/KIg4hI/OiZ\n+3dBHnRtXHHNdpv9EalVeJtw8xdVVRNERAqYccgZUFn2H/xuGq9YjncCdHvvO3ovsJo7G+m5Ht3W\nz81jz/emlXkEv/M1zMXRt7St3nOYi5x7LnryCLUAb6sJxg6sphdNNQboPVP0+ey3PcK/9b8oynLx\ndRXxJ6d+/xt6vb/+Q/3+5FveNvpv/x01F3nyf6jhCM1zDr6t7W+cbOi43lpz+7Sf6G/739QxD3va\nboz7aN7X4+38pj9/vac6jtmyzgvvic62zuPBN7StrbG3kl2s6nfHsJJuH+lx27veZEFE5PBrPvuw\ntlBr7J3vtWT+fuAgh/hiUTx4JCI1jivWDCLGzMAsaIy1A7vlSkP4hDWjfE8NeGhjz/UwQRZJRGTB\nmg2nWESlohrf1tadTHXtipDRKgrWg2CxwfeVNrg/+sZ6ivpa3Pgrv94xW8RxcaxdWGjTdCQf20yj\n3uP1XG7OOhQqcJj1W7DWxjA6WaBPTmkDxiuVfUK8NBEQ5BAhQoQIESJEiBAhTNwIghyVpcTTXJJJ\n9f/bln9LC9wSiKs7cE0zNYn9e3Ey1d/SEXVOibjiOATejB6pFNRCxLZAl5tnQGkv+EZt9BOBRKeX\n4F+C9+T4nHj7zi4MZ5dv81SgOF9UjuvHYPjRZ9XjsN+OQ81q2/E1x8E2Ti4a40rIQR55FDAdNSrj\nom5sAxa4CWyji6nfh2/XjkMGTia34Vt/XblCRCRndTU4yOTLss14uOS2LfGGTsTEvanX7E0rSDPm\nP0b7rmIbldIx+HWFUeVwupw19MBZW2NeyfcVESmAFMdOKxdzD1WDEuOy6h+syJYaYkxeLvuRGz6x\nm0twj6lawX34u50T8l8Hj8GvQ6aF11Iy13PePL7m2snxF2oV/Sfafran440Mp5r9zLZ128GnWyIi\n0ns2rXyffXTL7cP+t5/hvINPOXgELvWRok7dpx4N/hcfviUiIm/vAJEaT9E3XH/oa/u5R2kjoEeD\nx4rktvZQV4Brn/UH/Qd9tw/7m4x0zI0O+NEHOvbBMKu0LSKSTTWDM8Ba1UAWJzmsWk0PVg1ncl+z\nJP3HLa/xHCLEz4l4VdVPuLaI+DXDKbwwc4Vt7HrqAvfcYkct2pMNzdYU4NqzzXjTZ3EiqPa4NZLq\nEjWu/XXPiWR9DfviOQFkmmt0YcfDdql0wfFlPtslIiK3fN/ifawL5C9TLWNrVX8/RMbTHgfPNSoH\nubUeikysq+EciRgeNFRu4m1F56l2lKzoeMqa0lCIlyMCghwiRIgQIUKECBEihImbQZBnC2k8PZSs\n265+f2R4q666FRwpVvejqpyfy6bvUg5EKNsGZxPbpnwjpY6rcdtK+XaKbZfGrOalNiIq4Q+NMw6R\nOjqx7SgfKQNy6I675JGpCPrAdNpx1cho36k0tDzKlDqdWFTxTmaV4xPBbFjN3Itqe1RnaJ1ABYDc\n5AOvZdvAfGQHqEo+hY5vn8gkjmsrjftV5Fga1cpp159LjyY4FznybB0yALSCCg8VrjMdn6rIADMJ\nznmw9NeBQ1ypSEE9TXLK6LBm5tqiySKe08a2iHKWBh2JgUBQT9mhwOxzi2oTBu3GsYk4OHSH3Lhr\nXPFcX/DZjYP9gFrHYu9q5fRkTc/HZFn71NknB14/z/rm/oFu98qHs0pfxpt6XWRH+jm/vernAPOR\nr2gfRne0jeEDcJHXFXGZ3LGV7frdJSrM5z3d9lTpxbK2ru2PNvz5+fr9J9rfIVDloc796JaOrw00\niWodIiLpis7t6X0dY/eR3hP5AEg8FHGmq/66XmxC09hpJyM7dE5OMq6pWx7dZgZpvA4tZtQ1NJ1j\npP49ecPPdfcD8KA70We7d4YIUQ/qsltFIdwv1KYnAuuyVXQDtXUhQGNdJpCqEtiHa1vFmRLrNtdr\n9zyou5BaPXaub8yyXUwr+zjFmp5Xy7BosohIjn4nbIuZrpFHacs1ZPao1QwEl94KZQ/PK7vO49jU\ncY42cU9TKQeIctw0zwkg7G4t5rzxubCi/ahrNod4OSIs5SFChAgRIkSIECFCmAj/QQ4RIkSIECFC\nhAgRwsTNWE03UpnfXZXZoJqOb7X95wWEuFm4R/mzBKL/NOtgOlNEZDrQf/drRXN5F6lPSJ7Zwric\nRYAodLu4q+nXBEWAlHlbtHzKm8YDbK+J9Psc6Vkae8yMBXR21qnsQ9vZ7Ey3YWFcbuZguqr/pqxc\n4myk9fhJW/s2u+ULx1IcxxXp4XjzJT0ObbdbRuZttq7pLZquNI+03TmssxvvX5VFc/bGpEtcVgs1\nXPHZdZabKNyjsQXTbDkpCsZq2tE7eOyaHNt1Fgv1oj/XB1I3cLzPs2dgMWBRG1cc++utyCFHR7MM\npv6QhmPfryta4bb1gjtHWblG9oi0DFeQSPOcw+Mr+1Cgn1bstA+fQ65wsqKfG2e2yFX/PV7Tsbcg\ndbiARNx8Wa8hay7iimEaoF80S7SvbXRgjpF0Dc2EVuYsdh1j3gqcWxTX5saqfb2pc/20qUWA8QQ0\nI94uoBnxmhURSc6qknrTTVCWUCi7gITbfGBMTGp9o7xkBlOCyVC/XzJGDTkMBhaY6xTFx7z3GJE5\npfmqnp/pSmSs60OE+PzgelQx69nWIjJSu4qT6srG78vcFkyDgoB1KN9TmiApZKSNRZZewLXw58m8\nGclNFuO54mquvfw7u6ZCtSbhyeK8vEZbSGJ/nPJAj+Nk6kije4FxgXJhbbHrsnhSK7iL6uutHQdl\n6zgnfN492662GeKlioAghwgRIkSIECFChAhh4kYQZClFpCydrJQL8+ZJRJX2t0R9WFjjmjIfaT9t\npdJ0J7aJwjtjNV0k1f/zs2AmHReVfSJz3DnQbCLJzh4Yb+hFC+R+IydXOitjSqmh6ItWyUB07Zwk\nE8isXVK2rqxuw2IwO49mDiufOa4Jraj9G64bYwsbldVt4x4K/Mzb/v8rmTcgAdzGIb4s1ht4g4XP\nlHkjKss397qhiJjCj38Vmbe0eqlfJ/NWngNBJpJRk3kT2habgjtXOMPCSh53Ui1YtGhJ3EVWAEV/\nBQ1DiLibYkMGUZD+U90mRwYkG1FeEDJvp1bmDcfjdXuix+nDcMPJvMHiXMTIvO1ofwefwohme1r5\n/vNk3hj9VT3vTubtmZF5+0hl3r6yDXk1FMI6mbcD3afV9tkHSrEtQeatcVSVecuA/PYefrbMW06Z\nt33MxTMUMe0d+33Gep31McefKfP2xJ8nWt72n3YkCZ4CIb5gxMtq2lOazJYrFEPWiPdGgfXJFcoV\nV9diSphxGyfzxqLrDX8PXpF5w3HLcVXSzGbMXL/XUEgISbUc9s0J+lyMrIEHkF0+SyhvWVtn5fam\n3wcyj8zwlSyqRjFtfIy1y6zrV2TeIOsWYW45PivzxvmPIPMmGIcr9OtC/u2auQ7xqx8BQQ4RIkSI\nECFChAgRwsTNyLwtckn3ziQ5qyJfsXmLTPgG2KH0FxDkPuTRgAIXhrPbBAqbEGWCpBq5RhFROyNd\nk1D+Behvl2L/2xAWBzKa9D2feAEuZvYcb9voW4r+F+BupgcG1aQ0DhHdulQcBc6nfp/0ACjt5Oob\nuYgXUs8st4xvrg4JBXKI+aLBQnnijSgaHONQ3+YpbUdEXCAj5CSGRKTEGCnvRt5YAnSRcxCZ8XCs\nMcdzV/mkCUXeca6LZY/oxSeYd54zzqPpi4hHS7QdyNPd0n5HkJojZ41i79fOaw39iFsw/SAv1kqc\njXqVbSnDN31Fxfz/H/berMey7MwO+850x7gxzxE5VmZVVhZrIotjq1sUu9EU0IIhwzYEPdmwAb/Y\n8C+w/WzAfjBsAzYasCQYlmFBgmXIrW52N7vbFJsskjWwqlgDK8fIMSJjjhtx5zP44Vtr731uJFvq\nqoApZO3v5Ubce4a99zl3n7vXt761aMkcHViktABvnNchx30VtsEthAxf6FzTEO3NIUIfATE2/D6M\no2teke0qslF7oGhtBg462xIfY4wcHl/W0GtZvQsbVaAjCVCe4jGQFAexNjbb4AC2HiliU7kLe1uI\n7rfuLtt9cG/Gu9q2fEaPX99H1giIf7JlpQirt9WamVxD3ge1LYwtMwyPtu15gOpU8T0MN2BtjrHl\nvDCzaM1FCpq/oI2hDoHkQM+aRLf6zv0HfmONMpIn4HdSrgpjXD2ctecBV3GyVZOw/xSevg8fT4ns\nEubMQ4sgp+Czs07HPI+QyeihFobmWyI2o5ngOzJ8US3Wq/eQXZvU+aGzZue42hP9O0CG1mRKj8jD\npT21za5wru1d0XkhaUMClXzpJf1OhJ3yfK7vla2tQ8iwUaa1/cKM2bYKGVNmPyPUAR1cx9yyq6+1\nbfsbI21VSm3qz9ewTRef6zxXcX4vFEs6//cwLjVkoaL7+n0evnRO24M51McXKzyC7MOHDx8+fPjw\n4cOHE2fDQc4LCXqD0xxkB9ErsGozRhBAfYztJFDPMHNEyVE1bipwK2VuMLlGboVpEJY5u3EHphxY\nvZIzFThc5QCGJEao3KBKMKQgJ9nhapKnbILIKjmoOfrVcxBMVh8TraJiBNvMfrhoKjlYGB8aXAR8\nnwLqrrICTSuItBNlxjG4ag5dFQsg77QCt6fX/zNU/UcW2JUCCD8NOrIJfY07MNSAcYxr9hCMgCCP\ncXbNVSMP272mVF/A8SNya2ncQSF9R5HCIO8ccx4PHGuOY9q0GYtwTBWFxxu1yl+TwOW813R/spKJ\nUhDhz8F5ZVu1vZXSZ8GAJjN6rAxZldjNyPB7w34RPef3CkoUxYQdayrCGGts8McNt57mM7EV9R83\nhqFSQzGOxKeOyUwyxu+u4vtDHxmqmLiGA+M8XXIJuQ2r7d3zGmMaXFNWp/N9fAXDgZOBCcckJcaq\n4pklKBzbW2NNm43xDo1RCFRInDnE2IT3RqfnQR8+fkWMJjEHOPfMcBYqD7CTL3DbVVDv0p/R70rV\nedTxu17B/DaYharSoX63RzM6pwym7fch6gMtBYKcoS7HzABEkJ2sYTbTLLXBHAsc3hSmPZGjqmTm\nSxqPsL4F5kD8nKpVIiJ5DM60eUyg73PsNJ49IztHjiZoPqUv/Vn9P+5DHWoK49ay8x2zbMNJbNvV\n8augrqUP5anKdtkEzccXIzyC7MOHDx8+fPjw4cOHE2ejg1xLZPD8sgymgVgCBao9sehPSj1T6jSi\nQjzqUy9Y/6dOqYjIcAIapVj9hljpUnOYfEtXXSKDckME1Yrj8+AlXdJVY/UQussNex6qSwxfV75R\n457yeYeXF0rnHVy1nMPkhNrJ0FeFBmtyDKUI6iDXLK9qgFV30oGWLJAuHj/ZU45jb82qPlSOoGxA\nRBIo53AW/N5Ez197bDls3aWy5W9tT483gtZ0/XvvaptdTeNx21FaKFN/Eiv6p+oUp0C33/1Ej0uU\njgiEo72ZDcY0mH+V9qYb4N+G1KQEEmrOQ0vmp1ha8zzU/yxwLEbi8OuKMQ4zz9N8qPcOlSRyxwqc\n45XjviYvOiNnHOhm5mpvUvXjMRQuumXOnxlH5/pE4P7tf31RPwN8VLmo1/pkDRre+45qygg6yN+5\nLCIiM+8o5/nwVeX+NZeVjx20T2cfsmsXRERk6xt63eea6hvdfKQZiyffsWMw+z0dn+5LqmzB7+P+\nC9q/iTcVfTl+zfKWn/vuHRERGXxfzxN1dHz2X9Pvy/yRfhf6r5w3+1Qf6rjtX9d7f7LxoohYdZbR\nhJ7v0d+009pzh1oZz+8Lv/f1Le3nzpe07Ys/tBzDbHZVRETaz2m7a+BS13aQ2cE9dXTZos5z3et6\n7m9OyPAfn01izsezH5UffigiZUWhGhWFgGLyM3L9q09RuWFmKQU62/yXyrGnAkWEuWWmZetBqDbE\nzFIyZhfNSF0lJXWIl6lP6qXzZsi6RHfL+sgiYrJDzFiFUIYoNvRgnLHmHy2YXYrjsmIM49xHqjpE\n+2pXcaPG5wy+nxVmmjAmCTI+qVNvEG7p/Dl1A9k7qPikeB5O/IE+H7JReUx8fDHCI8g+fPjw4cOH\nDx8+fDhxNioWnb4kP/tUKmMr28JxuYm4KiZfkHw+cv/Ij0wcDiR4vrlBCIG8JmWepKsHafRvwR9c\nuAOdSXKQsXqsORxi6tGy4p2r3+QuPgcvszRY5IyxH9TvJa8Tq9fY4V3WyEOluxERQur6YqVbvW/5\nqsbVLStzT2vV8li7DnG1W7q6r4OPxur7Cvm+66toh0Ut8gVdmVNPuaiRAwb1EfKNjxwFB3K1qYZw\nSZUJoj3o+oI7zGOJiMTHWPGPcYTHVUBKuqBUfUAlNttA3WIiLeI6MZEvDlSZfNXogmYJyIHP5xyN\n5ircHU/APccxBpegvQmkMt5ziNhUOoBSSLak4xjvwFGPqi2OIoXhns8qghuTkwdFh+IFoKpUaRCR\nDHqmzU3dtruU4H9ta/VQ207enYjIYFLHY/kH+v0p4CxVX9PzJne29LxLNjNC7m90oP2poVp88mO0\nDd/f2gNH8QPXkNXj3VVwqnmJMS9U9yzx+ONHiiY/f4B7pan7UMeZ/PXqfaeCPmV2Rv+vv3tP/5iG\nrjPunalVi0QFQyhsHOu5K3twrdzS487gvi4cHjU1khvIuMTULe+h/RG/83YIol9qW+Ymr8pGz3OQ\nffwbxnXNzERdm8XpXcQc0kXGtFnW4Sc3ufbEzpF0bE0+faTH+LLOIfUHei+P5hS1HTbtfV7dwxxJ\nJ1o61naBWFOl6NCiudmKzhW9MYWIeFfPk0+BV+zUg5hnBpWsgNKGr2nWhdnR3jk7FzPTUz3Q7xwV\nPLZfgwZ6R79jzYcWQaanQrKnbepc1m2bGzpfj6Yxx7iKFJjPhmszpb6H93WuPPnWJRERab1n52If\nX5zwCLIPHz58+PDhw4cPH074H8g+fPjw4cOHDx8+fDhxNkV69apkr1yR0WSZ+uCmgNIpSHExTVRH\n+hIybJTbYvpIxEqvTDyA+DjEwjNsS0mywCnSyyso/utpWvR4DQV+kKViyiat2VR0gvRrVtO0b+2u\npqRHy5rqimBlO1i08jAsnmPRHPvO90PIbrkSZ/152NyigDCmTTBoDTGsbJnuERGJDyHZxiIBpPTT\naU1BpyhurG5Z6sNooVH+bF/bP5zS81f+5B3d0KF/BDtIw0s5CtIBWBj3lMI+8+/Ht3QbFmiEY7Qa\nEUmfYiH91HAKQ4Kjdukj04ZirLVuMcn4Z5Tmuv+w9Dn7LSISYn9SXUzxCgv5aKvqSuqxsIWyYdsw\n5eA2LEJ8ikV3cKDHLcaKGoNf3Dx1ngiWqLvPwS61ieJQ0Ha6y6D0OG7PpDjsvaEUkTkcv31Bv4tT\nuVJtgqFtGyeE4aqmJ9uX9bP6rkoD1rdRkPkle01Ii+qugE6CoR/MlS3UT85ZWtC/9+JPRETknbUv\na//wfTleR2GfDoF0r1ojl/pjFO4t6PF6X7mI8xUYEx3rvdftPTp9U78LgxnOL7pvExJ7u6/q92jp\nTXtfjhZ0rI8w1rWDBH3H/YzzDabs/ZZe17Y8+UpF0vfH7OF9+PgVUbz3sYiIZC4V7x4of6CBGUOk\noHxf5UNLWeI2/CZX/1/9fmYo8ItQZB070oRPs5Aeb4uISO5IJXK+rNMYBG1Ix4usnX3ysc9oD128\n/0np/dp9S9tiX1kYzfl14SHoYGi7KTQUkRhzMQvLm7dRyA66Hj9/2jMseoQCcIxXhveb34fJSMeZ\nWH18YcIjyD58+PDhw4cPHz58OHE2RXqjTJLNA4nbKJYiOrd/ZLZJOhQFB1pKi14UQtFul4VSIiIV\nGEMkWzgOC63qWGGPSZKJiBUjRwFaM1G+/pEAACAASURBVEPxGYrqaKOZOEU5NNKIUXTGYqkE/WCB\nVy11igHbuqKMgOhGsPoNj7HSxPnDui24C/tla8+QhWQs0gJSWnGQgoLH4yocK/OkC/trFIEFe9bG\nt4IxTqq0DtVjhCeQ16FxgzNu4fRUqa8srBqXS8udFbtBArCaDyEhZIxdniJHVAwx7nkZUS14z1Ca\nx7VmRsEWV/umIJHtp0SdY3JB5IHGMURpQ9hW8/xuG02xHyWEaP6AsTEmE21HgojFKJCICydRUNiG\ntTnG2pWQM2gzCuK4TY5tohm9Z9Nti25zTCMAnSOALdFQxy05Rj8dX4wM3andLduSM5sSnQAtcezd\naaATYJsgg5xcG4Vq+B4Nh87Uwe8c/XuAbucEz1nI6HxNj1NkdpD9oVVuAKOgooIMU8/Zid9HDDmL\njGjJy4g6biYL7aZ1Oi5DhIK75IRziR24EIg6iwHZJh6jILrlnCY+1OtTaTdL/fTh468KMx+5c/Gy\nSjmaImRuQ/SXc+O+U8BKu3rMXdGCZo34TAknbPbT7ONIpOnGuL/ZFs5tbttQMG1Me5jdG5WLrAOn\niDynZBuzbZSeQ1bMmPY0G2afAoW34a4+11i0XaxoRonF5K4NtimUB9obLuoYUAaU41g4aLCZ4zk+\nGVBnFPUHqyoTGdy9Lz6+eOERZB8+fPjw4cOHDx8+nDgTBDmvxtK7siCjyfLhqvuWU0RTDxp5FJCU\nySplyaS05vD66hA3j8r7kFtLW+rQ4VDSFjiESUL7gv7ffAKJrumy7aR7ThoCVCiJU4ORA3nRJQrY\nVKlfRJckb+F/dtzyuTKYoNBMRIom+gFO8pEeszdvbS2jga6yyVMmx3o0BVMWIH21yDZusKzj3p/V\n9td2sTpGW+t7kL5zEQQirAtz+AzcLyASRFGjumO5ib5lRDqJ4FLGDki2WcmLWPSVqARl/hzxdv3c\nIq5czUdLKt/FbEN+oOhCgNV/4aDbNNYw6Db/742dZ2XRdmcbhiSTENOnLFFLkQdmDQInK2BQj7QM\nG3K8iLJnDoIcox/CTAiQoICSfkBjIgf1Iaoz87GiSkZ2D/dFd03bUdu256FEX4b7mIjUzIdAldqK\nyoS3LQqTMosBtGfpZyqLR5OM6KFyrCd+ctnus6kyf60Pkc2gocGhcvrzjQciIjLtSCv+yQ9eExGR\nF+5saNtwLy5kKk9VfHJb23Fh3ewjW3rulR9h/HF9Kvc14xMj0zD7keXwVz7Sc9NeNp8Acn2gY9GC\nhXr40V2zD++V2ZHyHaMjfE8OgZYBaVsbrdm2oc+th6mZe3z4+NdFsK7mOkHbkY5E9jE/D+MdSEjK\nATKpi0BRJx1UmBk4ztuwsw9O8OzEnJJfsGY9EaTZjNwn57UTnA91E+68aubc5/R7GjC7BwnJYFaz\nX8W+zWhGS0DEgdwGizr/jZuBDJ9fMX9X7uh3vUA9QFDocYdzOs9VtnEsZ440EnMjPN/wfsA5ns8n\nB0EOn7soIiLZlPYjfrCDYyDzBCv6cM6RwvTxhQmPIPvw4cOHDx8+fPjw4cTZqFhEWkE+qperbKNG\ndGrbUZNorG7LfYi4pg5ASWSXNtTG1hlIrOFSOgYRIwiM02aXfMisAm5UrbydbqOvSRdWlBm4yLBx\n5raBQ5slD9LYXaes2C/317zvtCGslhGmrCjzPtlfbYN+FsflfoxQsU9FjKJqCZFEvDm2cXOMAwqk\nwG1qQbS0MfYZ+NEFOOPiCMAb1AKIrkFWjelHUDqmiF2ZE9E4xVOm2oPLUSb3s162EiWHznCHHXvT\noOHcSO42NHjBefKmPX9EvjDbS941tgnRr9K4cdu0rKwRpEBtyb91+kkTDJpjhF3tR4i2Gd5y7PDk\ncW4ixgIrc4r8RwN8FzqOwgbtySu4wcnV7g1LbS2canjTRtqzdsrXg5y95OQ0Skq0hdtUoA5jONc9\n27akTWMdoObkcEOon3begYPM06qW3Glj2MFtcZ7YNeqgasoAGRd+Twpmn7JSm0XEZlMw1qxnKMbU\nTWgo40Y0KErzhA8ff1UQuYxc5QjaRiPbyVkgwvcnbYEnW3HUJZBNjWkONaGvYY/ZQzwTpt2aGMwl\nNHxqYJ7jBmxTqW1QjJnEcwKfxW1Fdo2Zk2NCVQDpNsoUU5rhDPPy3EKlGRGRBPNqivExyjHTCcYC\nbXXqddJpZrBQX8L5FN/9HJm02Hk2ZDPa3uE0DZKQLeR8x2dOdcyczMcXIjyC7MOHDx8+fPjw4cOH\nE2eEIAcymIxkMF1Gg+OBXXkOJ8q/xYkUx6D3DYn0OsDfEAWz3UVYAON4PBYr9kMHAEMRqsQ9oL+g\nQR+vw7ryEO837coz7upxuwuwqj3WlXV/BivOfvlzEZHKMdDFMZSZ71NdwO33YIZatXgFHZbbRgNd\ntfbmLDJQPaJfr5TOx/HqzwChzC0y0FkCT7kF69ARUWf9v/HnyhcrnOpkw9UF3yzrla2aA/DFApeD\nzMpl6kvefySlwL6hw/vNgdQVXN2zGnpcJ9jRTia6F2yohrG1E0f7ybtzUECivdwmBI89OwQ3jvqX\nt22bU+gSG3UJ2qM/UY51Pl71LSLBfqXUXqPgQYUPw013NKehkhJsA40hzxsIfLapFtBhzUF7UNm+\n9S1w/AJeWz3G8UXdbuK+5d8S5e3PaV+XMuX4HVxTRKe+p2NTn7W1AuQY919W7vGjb2s/Jm/pl3F6\nStvU/q7l8S3+ifIa219VTi61xje/qdtevKPv73/D8h//xu+9LyIid350TUREKns6bk++odztlRM9\n/9GXl8w+E7e13U9+Q7epHIF/vwKt4ynt55Pfsvd185FaxQ7mKthGr1NjW7/ju68oMrR+eMns013T\n8Ti6BP3jPe17YwuazLim+9ftd2FiU8+59fVIRl4H2ce/YUQ3VB2B9RoiIjk4shVwjnPwk6khH+7p\n/FGqUSBiSzT4I9Wk5zehwL5Vl09MNSDOxZhXM86rfN/JfuUn2pbofX1ecK7kvE4FoLRjPRAizIk5\nam1CavmjdoFKQ6237LMyfay6xBGUJ5hVa92CktGRPo8KJ3ucPMR8iboWKgmFnM9Z4+Eg4vE9fRbG\nG8jeQhUjnNQ5ILt5R9sxZW2wfXxxwiPIPnz48OHDhw8fPnw4cSYIcjTIZfJ+X4YHY056uxY5rLGS\nno4/5ATnZSSW/GIRkSH4ypN3oWmLFWjawHmweHRVLNIm0OY+1866eqweQaECeq6jpsPvJB8RCC5d\n6aI+eVa6XXJs94lxfDrpkSvM8wbghtLtT0RkeKD7JydZqd3cNt5HZW5uV6sx+JbBENxdqBcY/VaM\ngeukF/WhwjFJFQvq3Y5xwh0E2aCmQBHCArrURG/rZU6vngjccCARIbbJx1BUVxPT8FGJbZCnPF75\nn57mdxokIyvzRokuuEFEpkiBJJ+MOSERsXa0k40m6ZhjFTUyjf6t66QXl9FsM07kWOPzvKS9WR4X\nIihmHIEcFw6nOt9RhY3WA0VhsxqzEbiHMlzrA0c/mgonh+DmPlLkaWJSx6u6pWhQeGyR8exQUava\nY0WqG49UgWTqzgD7KHKTb1iHu3xf0ar65jzOq22o7eIegjJG87FF+H/0QBHbi5vITEATfGJTkRvq\nfzfvO0jUjqL/9R1VGZl4CGWNDjjPB9qv43NWTzXZASI01OtSacPxElXwky3tZ3hoK+rr5J4nilRX\nD/T48S6UBvB5fdne14272sfJ+RmjtezDx782qN3rfNfDJji7cKjk/JN3kaF9mqYx5rEMijhEPDOg\nzwFQVbc2I2A2j+dm1s7l44ujYyxi5sYAbSRf38xdjYaMB+sL6Lo37gjIbKI4KjcGsWUdBrWf56Dq\nxIydO6/zOcMaAmjSU1WJz48MCLyIMwdTjYhqW0DvI2j7U0nJxxcrPILsw4cPHz58+PDhw4cT/gey\nDx8+fPjw4cOHDx9OnE2RXhBIHodSjB0td+xbTZFZpVxgR9MPfm6MQ0Qkj3l8vOJ4pGNQ2sb9mc/j\n8jwZsjaUXrI2sY48DMxLavtIrU5QZguyb8YoxDUxIWWEJ0b7uW21bJ3rtoG0ksKYe2BMasnY+9bk\nITLtDkvnceklZgzGCvoMnYXGKjDCKMbNOUQkYGqLxhYsIKN5hpseG5MJC1pj8j0scpu2lJGQRRWj\nMYmhQTmtVzIxQRrS2JySYsECPJzXTbcxnVb00XdQH0LK1LGNTtsCpOaCWtmIopjRbVi0F/Yda2Yc\nNxi3zuaYsH+OlJoZS6Q7Q0rO0d6U6T5Xfg19rW3rNuNGIXnltFEIKUmUg+KYVreRDgW1oqABhji0\nlQN9b2JTBfIrR+X3m4+s+QstsuNd0CUgzTbxGJQbpF8rO/b6DDdgAHCwUWpb/YlSHlhgEx20bNtg\nMtPcoiQcpO8ONY2cjPR8zU2HDgS7+5imNaRNwfSlDhMdWvKK2Omktq3zwK8yCqlv2bYFGIPGblaS\ndvTh46+K7+39/q+7CT7+mvG35/5TERFpf+d5ERHJqvpMoyTmwVV9Zrce2GeCkZ2F9OrcX2pxeOe6\nUuZqOzDD2rT0D1OoeO2KiIjc/Q/UYGX+Fzq/tj5W2t2n/5Wdh67+R78QEZH8qy+JiEgIqc/Hv6XP\nsNX/8W1tx2++bPb58n/3roiIfPT3nxMRMaY1R7+hZjCtP/5Y+/myNYeKb2vb9n5X96nv6/xae6xz\n/WhW59mN37PPymv/kxafZ3Pa3sGsPqNrm3q+3Tf0mbDw/9wy+8iiPn/a1/S5UH+i82yypfM6f0u5\nBeCTt3Ru3/zNltSW1r8inyM8guzDhw8fPnz48OHDhxOBK3nyWWNycr1446v/mTGxMET+1K6gKof6\ny7+/CEvHnq5s2uexikARHdFcEYu4Tn6qqwXaTBJtjo+Bao3seYZzKHAC+ttZ0tXcLC16se9g3kpo\nHVzVVc7SW7ry6C3rZ1ytHF/Q/1sbFtXsLZWF0utbisYO5rQ/NPKob1tkNO4A8YIZQtaEHA0F34nO\nuvbUDUrc6fhkQJBzIMhcsYVdixxSfL63oq8sCqzs6rYHX0Lx0ZEdNxq4UKovpPso7Le7i1HpfRGL\nns//XK/P3mt63ImHulGKMTg+Z1MLjW2YLAD55vWutMtWzbQ21uPo9Tl4Qcc26ej4tDZ0m+5KuRBT\nxJrKJB0U62FsszFkf+c1W2jV3EKbgAhQprB9CWO9q/9XDx35whbPA4RgIkBb8H9D/5/92KKnnXW9\nLh2MKSXCmvf1Hj28pivsxo4t3Kl/rCv2bEulkVi4wyIcSsSxyFJEJJgBGgs5JfNdJwKP1XfoFCoG\nKErJdlTuLV5WmbVsV9EKovbRFSuLJiggZFviVazmKccHe9rMsdPNf/MVPfcPfq6vLO4BEm8KalA0\nKGILHmnjzayDKSKi9B2sbEVEchTkmEKgvHyfmeIlZwxYUGkKMPPyHMmiymjBQdHRR4ki+Un3D+Qo\n2/21aL298cYbxdtvv/3rOLUPH1+I+Nsv/5ciIpLf2hARkQjz7LhEnFs8nq2hgJmyfqbQvGw+5BY5\nBihITDd0H865OeRUTSH6N75k9knu6lyf7ag0afiCIrw0SYkeY67etUj1wd9XkHX6f3sT/YFUKAvP\nkdFMIT8qYosboxV9PhTIfvK5YeZiWHmLiOQPHuMPZJ7TskEVi/zdov5sTHrVCAvQ9AryrcGFdXsg\n2J5LEsubh/+XHI12PvNc7BFkHz58+PDhw4cPHz6cOBMOcjDMpPLoyHBozfsDx/oXHL065MpogzuF\n1QTtY3PnGER7w21dRVRpkctVA61rHTva2oC2ukBC4RQS7QFlAkIVOm0rIkXN4m3wK3uwtD1SJKlV\nTJU+FxFpcn/SbbFt2FUkr4p+RIdWpsrY5sLYIj5BX41ZBrnJdt2SEBHEajGhvA2OH+5DML1rzxMP\ntM8NIoTHkMnDKq8FQfWobeHgZEpXaJU2jUd036QN1DvV1XDcdVBacKVDyG81N3WlScm5ZIIraIvW\nU3LO2iDDMhvX3xhg7Duc0Ak9bov22h3dN3mC65Xp9Yu6ZR6ziFhbZfKJYe8sQJCnNuxXgCg27zsr\n5af7UC6NRhgiVi4wgbnMEFao1X0972gCZjNPLBI6gXNHfV0xk1ccPdFxbMzgfI+tvFIOBJfoqczo\na8SVNC1mHVvvbBpyUduKJhRARqM55XVREspFOngfEVnNVhT5CIDkElUdnHcMSYBo0LigaAFxmNX/\nI5zfFdvfv6ztnPtRXDpuQH48DAkCx26bqIEsqsRccfteeRtKZi1bCbrgGAj7mByfkaUC2iOOUYOE\nyJYQSYFMlDGiobzhoh2DHMh+vLwkMvC4gw8fz2w8ADcY6OloReeBhHMMrLVHU7YWglnp1gZsr3f1\n2RWfU+QzfQjDqrqdv1lzQWS184LOxU0YV1HWbvu6RZ0X3td9onmdA4fz+tnJqm47s4G2L9rs1+7r\n+jya+SeQvIPcXjGnyDjrOFxkl1J9g0t6nORnn5a2Yb1O74o9T33vsHx8ZABp3hUuYF7vO3U0eA5F\nzErSFKyLbD5+H3Uv27m4dntDj3f1ksjJ5/uJ62dyHz58+PDhw4cPHz6cOBMEWQJRVHdMAFyip/z+\nHhcJp6oB1AVc60gTVB6IyhznU6/O31SCKMYP95R9ijH/DOG+Yfm1dB62KRjjcLMf4219Wn+C8vHJ\nuX76efDe+HGf1rbxPo6NaY5jRLG9PqavVNAwAhtQwgCnN3cUNsjztn1mG8v94r66DyU2wtIx7HnL\n94P7GY9jth07bxGevt+CsXuQ2wSA/t225WN95zhRTcWOwem2sV+mjWNtdbMCNJeh6osZx2hsTJzr\nY8YDWQYqVBQ0PCF3N3PUNMg5Hq8zyMvvP7UOAcelOsf4NiV1Ft7HbJvh+44d17ETD1N5emRljrDL\n/w34PR1ri7Utx3ZO7cOpnvH4T7EAPxX5aWva0r5PHTevYOHDxzMdzPjSOpvzDecWZIrdudjMiVlZ\n7Ujy8f+d+YPPQjO3P32+dudSIrcFz4OXkNPq2DFFRMIh3xt/TvwVbYv4m+VXPFvwYyYcuc+jsWdJ\nMXb8tDz3l7bhc+jU+CFL7jyPzDMjzT73fOwRZB8+fPjw4cOHDx8+nDgTBHk0Gcvmby/IsFV+3632\n5ypnMFVGS4dT/Fy5N2nTUXCo6N9z76seXwpKD212oz64nA71tD8LXiwWI8eXoRl4a1VERGLs05+z\nyOFgThvTWl/RfY3tMfT6Zmjra7k+GdpChDrpwNoTNB2i0lHP2oJS9aHSxkpwbPSTE7Rtxq5bQsNX\n1f9z0EWpNlE50gFsPrGrr5MV8H+WdZvaLji6UGWYuYGDOUibsRA+p/2oHJS1bUVQqVuzcHtIO2/w\ngKqwFifvN8Zr0rK88ghKHuQgB4V+Fgz4/2l0jjzrKjhdBkGmRTj6EZ5YlZF8umzHmpEPCztv7hsN\n7Xka95UXNgJvi3zoxg40iHegv+uuioNKadv6dtlnmCoaLpqQYwwDOrzCKrnAONYftPG/HetgDRws\nIsnUjQZvq3dBOVj1T5+YfcK7WjU8+MaL2v67u+W+r6jaQ35zw54nKStFZHVcu1dV8zNCFfZgxl5T\n8uKpH53f0W1iOa//o1Lb8KfFfpfJ881RrRyhcjt7otXQ0XMXzD7FY+0bbanTb6nWZ/WWVi2T+9e5\nZM/T2Hiof0ClIljWPlMXebQCq+mffWT2iZd0m6Klxwthe51TZ5t1DHuOfvSXr4uISG+uLvmbp63P\nffjw8WxEek3nNT6H+EwbXVJO8t7L+vxYfPPA7NN6V//e/neviYjI3Af6TMvwfM+u6vwe/uyXZh/y\necPlRT3+BHwZvqtzzdSPtAaju+RkiDnPYe6K31FucOMrL2ibyd29aOs00ikoE53T30j5Y1WrKNah\nBnTzrr7/tZfMPvGnD/T1SJ93u39PVYnm39Z+Duf1/LuvWN7y2nt8TkDp64qej/VgB1e0HmTyn//c\n7BNCBWM0r5/FO/g9Aj1+2orXHtgan87vqSrH8Voko39Wrov764ZHkH348OHDhw8fPnz4cOJMEOS4\nV8jcR30ZTpYP57p6ZWPOc8bdjRQTuL6ldfubfdjU96buAJkECpdCG5j8WNdNrrmpq5RooO9VDxTN\noUZupQ3kaMtB58jTgcJGDSoM6TQd1fSFigQijsIB+bHoT9QHukQXM4d7OpyC4gFUGNhuIpLxgVbW\nD5YtFE91h3AIPiRQxeEMnOKweKQbjYhI3IOKxY5uW9vTFS7R3/gtXVWaqnwRyaEAUIf7GfUZM2wT\nEdFzeb5A0lIqAmzpvhld8HhMqBiIWLc4cmfJmcpHY6TU/DQfKabbGc6bUXEBKgyZ058g1pVjBq3F\nEKvxbFBGeFuONm+B48cbZVJ6lU59WH3nzjGqOC7VEQzCO4LSBfqXdqwOcoLxqKDd1PHN6QzIY6bO\nmKCSufttRYPp3hTDvelkTe+t0eSa2cVmQhDgePVeVLSi+gSqFsiciIhkQA+CJa0+3vq69n32lzq2\ndSDZW9+098GVP9bzpEQEUt3myeu67xJ0KQfPW7ej3u8CCfhLRYyjpvbv+FVFYSZO9NpmMzYTEPcU\n7T34hvax+VivQzYPtBuqKbsv2+/phZvaN2qDp9imsq19pyb19P0ls08+rd+/7iVmU/T/ZMfeKyIi\nRy9bFKZ1QxGM4/VEcscN1IcPH89WxDc1K/XwP1RUFslvqeDx1H5e59n+7KzZJxrYv0VEAvzWePIt\nnf8m7+n/8YuOvjyzdZcVyX3yd3UOnvxLKGW9qPPgt//9d8wud35f0euDr+pcGw11Xnv4XZ2jX7yh\nc/LO1+3cdfff+Z9FROR3/sl/rG2Y0jn30d/S+e/8np7nZNUqbLTaimpv/F2dk6du6XOod07nyt6s\nzsGV37bP/tHbmg3sLekcPJgM0Xft18EL+v/UVTsG/WUg0a/qM7GxBTWQ+1BEQjb00bdtdn/pLT3e\n4fVAMtvkzxQeQfbhw4cPHz58+PDhwwn/A9mHDx8+fPjw4cOHDyfOxGp6qrFafOPKf2J/bhv5Mvv7\nm8YP2YKmQ8OOpke7lxSir+7r/3nVoT6AgpA8UJg+nyvD6uExUvmOPEg+hXR4lVQE2Eb/EjaJKELK\npifMPofXNS0w+1MtAhpc0HRI9YEKWHef0/8bN510wbL2wxhqPFZyerqo76ctUDs2rdlDcKxpY1Ib\njLlDDYVeVRDsHdvofKqBsYCt5Ji0WrQJy0hXHgtC3BzrYACaAQw9nvwdTWGwWFDEFjeyAJJRQaFl\nfx6Wysd2H9JiFt/Vfj35Kgw9Hmhbhi1tY3fZHrO2Uy6sZFFjlYWL2LThWHSzIOzwSlRq0+R9HRPa\niSddV1ZHX+Nu2dq6P4cxRnHE/nV7vyXMoKOLtI8+vKavlX1QRnbsGNBaugJr6f4Ci/UKjIH+P/eR\nvaa9BW3DyVqIvqI/d/R+3v6KjuPUhqVYtN5TgffiAMUINMugaDwoHcF5S7EYrsFM5C/eFRGREEV0\nAegaFGiP1+0+5l7cUkpNsAqr6U9v6bFYVHdx1ezD73aBIrb0hXP6AeaBZPOw3HYR6fyNq9r3P/tQ\n20bhehQfskAug52riEg0C+F60D+yj2/oaUCnoXVpvGbbRjF6ygXlMA4ZtyyN1iz9I4M1N+27jUEJ\n6VKkBZ1btOd59xPdp5LIT/p/KEf5nrea9uHjGYzvvv5fi4hIsAXb5kugM9yC2QeocelLlipw8LzO\nubP/EHbOk/pbJgB9L+Wc86WrZp+sqQ9HUjpGL2pxYPhDLWLjPNd5zc7f9YcwRkJh+8FvqBEJn6tT\nt0Cr27RW0w/+nlIf1v+BzmGc20P8DklRIBf+9EOzT7Sm1LX+FZ0D4794T7dBAV4Os4/oxStmH2Ps\nBopkvqPjRzonC8SLF+y4BbeUZhLChMpQGGPI2WGfky8tmH0a/1LbEtSq8pOTfyFH2a63mvbhw4cP\nHz58+PDh4yziTIr0smokJ1enZNQcQx+PHTHqFUXFhpO0MtZVCWXfuosoMmo4xg1Q6JiDnW9Wj3A+\nyKsMdBXmFukNZmBZC4SwfUH3mZpaxz5A+mYtckjJt+OXF9E2FB09ryjdYDrE+S1ilNbKRiTJkqJN\nWYXGEPr+cMpaIBYBLClPUHAXlceLNs7DCxbdJhLKokOitgOMY3URtsTbfbNPbxnWlIu6TX0fKOq6\nIuXz7yriRwtqN0aLsN1mceAB5GgWp0+1mWMcbig6v9rRVZyRv8Iqb7huCxSSfVhiY9VY1BWxDE/K\nbSmObVEbRbMaD3WlzuvDVXDtIe6DI6fgDpbLlAQr6rqyrd3AKhZZiOTEFqjV7yvCmU/USttMPIQl\n9K62KehZq+lsElI8rvSbOIh/BbJp9638WmVVx6m5CXvvx0BWj3Ss1/YgU+YULhYdFCTOlD8LYN+c\nruoYx5tWWqh6Q69L/opKCwX3FYWm1We8pPdz+mhTxsMgAZPa9+jqZW3HA5WO663b4rna+ypNFMG2\nOfrFHf3ggiIb6Z0NfX/BrvIpRdgAypzeg2wQ0Ozsxm3dZ8l+5zIgDjFQl+i6Ss/JYy0CDJo6x/Sd\nYsDkh7/Q/gANpgVr0cf9Btm3FGi0iEjU0u8Ax5bIuEGfef/VrISRQCIpXZqW4sPPWRniw4ePf2sj\nPNR5IF/RTFbYx1yPueT4BZ2jWzdtxmzhpzp/9777hoiIND5QVLhAcXJ05aIe8+Nb9jz8A/NRf0Hn\n7fq3XtV9P1T5tf0XrJTZ6h/fxAm1bdN/pvNo/1VI072l86FcsvKZx1fxnKGh2C9QxH9d0d/gR0CH\nr1hkN7unaHkyr3Pk6NuviYhIDc8cQaHz9jfs75+F/+N9PR7m7+A8kGrIs/af12wl0WgRaz+dL+px\n+Nsi3wUCjmd0c8Laesv157RfVyYl+7M/lc8THkH24cOHDx8+fPjw4cOJM0GQo85QJn/2wIhUmxha\npK2ANFaTXBLKoM1gNQFTiaLqx1RjhAAAIABJREFUiOzTzvA+pKeI2NBOkVJajhxWY6JsENG6Cx4m\n0EbyXSZadjvyiZO7QPlwHsp6NWfB5T20fGKu/BgBZKnMvhTs7ljzCmOXSDmyEDAzV27gRVZj57Kw\nr+hjAA5Ok+fBeQtHRqx5X8e0OdUqtYHXID9nETYGjTQYlMOKAiCUTe0PkWURkRyScyEk2bhPcgJO\nKFZ1eeJYM9P8wliCo39x+X3XItrwURtow/GgtK3Zru4gemOWxQHk3AqMCT93ncJHi7gXUyDjfQjA\nT1CSUI9f3XNsLdHOoKvbDue0z5W9rNR3Vx4v7IODjvEy9wraNJrT/lYeWp5Yug++MFbf2RzMX3YU\npYiO9BpnS9Nmn+E0UPOfK9KQHeq28UXIoj1UNDhasJI/REspvzeY0jbWbioXjPxlV44xZPub2u58\nFeYlyGQ0IckTOIjrcLp87aJFmnM00KaFUntELAo8WoU03DsQ1TfWr5DJyyzqHPI7QOk8fP9z3A8R\n5otoft6OQac8BjRAMT3GfTe4ZBHx6F8pOhJVEgmeZpnqw4ePZyIyGBYJany66zpnNe/q74P6E30+\nnTxnDYu6Czp7LP+hzqPpJn7TLKv5RvAJMmbn180+lB0V/B7ozUEW7U2cf1LntpFj0Mb5uZjROff4\nBZ0rjy7pXLb+C50b85b9/TKxhMwY5rXwkqLNwzntV/XyRT2mU0MSIlt48LyefPoP1GiJv9+CHdQ9\njSyCzDoTk90FJznf0+dcBYZm4cVzdgxwTmZiaQYV8tmP5+/Oa3asZ//3t0REpNF8qcQu+CzhEWQf\nPnz48OHDhw8fPpw4EwS5qCUyeH5Z0nrZYIGmGSIiMRC2wawiOeTUdpYVfUq64P06Kgo0FZkG+pYC\nEaM5R9xVVNXlf/L4jJM1Pf50rcxNHszZ7Y7PabvnIuWjjloQuT7SNndWIVK9bbnBg+kyWl7dU1Rw\nNAmDipq2uXpgUfQA7aQ1JZU2DApJVN2xGDYIJKyYaUiSNsBB3lEuJRFEEZEUCGQPvOjKkY5T0tYV\n23BW308cxRCqh/RngRzT8AQGJRwTnlcbrC8JK3EngPASOcaY9+fsbRbktdJxM2yTkNuMlWHkGoeg\nUpVGK1kVahLgAtMaOjm0POa8AsMY2jhD/YPKKgHQfHLfRUSam7gHW0DGR/rZYEr3oV16OLL3zghc\ncI4Lr7sUUIoA0hrvWCHzIYxgevM6Xk0qoXRbpbZnMxYaiI51hZzDZCRsw1ykp30OZ2CZvGtR5zrR\nBKLyCYxJtrZxUJxne8fsYwxVgKLW76DSGG3M2spxbt1x+N64b7MnetwQ/N7mAdoMQxdxDFZmPoWt\nKTMf6EeEV7OPE8yixLcU+RagvxnQdVZBJ1s205MBnSAabDIyQJuJUGcOOkLFC4E5DlHnYoTsCcaz\n+qmdA3Lwn4Nu33CUffjw8exFBOvnYkNrN1qY24n4JlD+qdyzqlcTUNdiXY5RFLqttRfMpGb3H5p9\niAbn+zrnzr+nxy1olLWlSPLC+1bFgmpG+W21oZ6EclZjU2tUcmQRAyczJz9WTnO2+7F+hm0qyLLl\nRLKdyDHHz7ylbQjmFClmVpJtn7rt/C5BnQmNvQIg4wWe9RGUNzKg6yJ2no7u4vnN+XrM8Gv+TYd5\nMA2ltIOu+U31WcMjyD58+PDhw4cPHz58OHEmCHIwSKV6d1cqcfSrN4LCQAOoUkCdvL7yFeND2PhW\nXLQRdsQPdZVSPZosHxMcYdeSt7GnqBs5rZUjcAxvo4IfaG285yhFFLq6qtzR80TL4Dg+UWSqmSt3\nJrlvkbYY9rZCJYddXeUl4P7k0DAkR1REpECfiaSR2ygJkCiOn6teQL7OiDrI6Be33QFi6PC940PY\nMR4qqhiA80o+z/ACqv/Frrr6sIakCodAwzirQRlgRv93lUmoqNEAH5tobDjU/4muEoEVEQlT7Ws0\npCIJkV30F0hyNbXnGUHLujcH1LwN7eFJcFKBbuex5VWFuC5E51lpPFzQbcgzpk6xiEgeYWWLUydd\n/awHbWOi+bnDER81kCkAqtibh7YxDjsEf7k2bTneGbIAo6a+DmaA2h9pf07W9P/JoeWyGonxBpDo\nRb1nA+gVU5WhWLH8W9p0Jn9uq4JFRELoCedAfF3dYBNAEWj1XGzo6p86yMMJe+9UpqdKu6ZX9Xi0\nl6+Ba1Y49yhVWJroTzgHpRNcr4iIxINHZp8I58nXwU9+R3lv5BeP885FHG4xeP4FlCiIWrBN8Zpj\ntw1EPQBCTW44K6bJCRxdsvbUwY9RoR3HptbAhw8fz25QjaF/SeeY2k3MD0Btey/Y+eHoss6XC//w\nTukY4bzOe9ldRXyjF6/KeETbmsXroKaj/h7qUVahRTxlf3e1VlFfhLnq4Ou6DZ9zi21Vr+BvAhGR\n/jxUeTC3F+e03Tmzbphv5UOrsBGv6HlOXtTPan+gvN8Q87mps3LqhOKLUNJgfdEe9PHxe4i/j4Jr\njnYy1DIC8K05J4dEhpE1PHjd1pC0/k9tZ1ytmlq3zxoeQfbhw4cPHz58+PDhw4kzQZAlCKSoJKYa\n37ztIDqsYM+r5VOSU0u+al4bU8IQkQScFbqmEA3i8Q2/UBwnMPKWqXxA1QmsrKi/K2KRUDrQmVUP\nnV2isc/FUWOIsWo06hXYh5xXZ58gKPNszfHIi2S/AmcM6Bhj0KuodB5ymVxHRI51VtfjcLXF96nD\nHJ9YRK+CPpIzSzc58peLSM8XO251HBdqDVfbetzkGCoNhZ4/rdl1WHIMvhH42OFI+xN3gJpjaMKO\n5ROTn1w5Bsf0BPtCUSMBUklutxtUogiASCdtKBNk1EG216d6XEYgoz4c9I6AXMMtz0XRDdrcAaca\nCHx8Uj6Wq/Mck3fdidAGcOkxjrXD7FR/jNsQ7jdWABMJFaCozMxoX6EuwfuYvK1heZxcBZRT5xuh\nH7xHe5q14fiJiBTgC/N7GB+xr7VfeXxqWRNpMOoZ/B6BS1c4fF7Dt+7qPvkYhy2gGkxoUYvxthl0\nF8or/E66ahlmTJmZItrM/6Myv11EJHerqn8tHno+fPj4/yPMHIhnr1F2oqoWHHIT5/la30MNFH8H\nHaNOwjh9Yl4/eArfF5lyKjIwC85sWOCApOPKF/VttAHP4mAfGW0H2eX+rPsgF5iKQnzWZM7vuRw1\nMHyek1dcjD9bHN+EAvsEyJibOpC0rMMcOmOQ8XlmMn4YLz7L0M/qoVUUKv1+Cz7fZOwRZB8+fPjw\n4cOHDx8+nPA/kH348OHDhw8fPnz4cOJsZN6iQPLJumTNMj0ickwlAlACsgkU1ExANopSZ1OwanYM\nCFjMFB+g8K0KaL5KAX8UVY0s9J/hOJRaosRY3IUMFoq1WPglIpLHoBfM2sI9EZF8CgVKKM6iOYOI\nlSczS4wQBUTYlvsEU1bei+kGUgNkzGqaZimmDyIiSH9QGJvUDppyxAEkTfbssbJZHa8h+lihtBno\nK/UHmsJwTUziHf2M1sIc07CtaZfkACT5pxRC0faxeUv3ZcEirXijji3iig6QSmfKhCYT3TGr6baV\n6goP9DitQgvQeA3licroVAYo/DxxpMGYfifxH9SUmOkbpLQma/YrkOxp2zjGpGUEufa9so8Uv2PR\nXcX9zDZVkEoLT0CBIGVoc9ueB0YSEwO9v+IdbVOxp+PWvIUxcYxpmGoKV2H5DdoEixfyOZhx9Ox3\nLoS0YriiRRdGggcpwBCpLVIXRCwNg9SdFIWQFYi85wdaWEHbUxGRBigUEQrtAlp+T0PqDmk/moGI\n2GLGGVwnk96DlXa+o9eW9tUiIhlkhwT3cwQ7Vab7AhiJDFZsMW/l7gP8gbkC9tEhjVuWcIwNK69k\njE9QEEKbb2F6jzQNh2ZCe+pibVHk5DRNzIcPH89G0ECsWEcxG2ijxZzOzd3zOsckxw6FkVTFK1qo\nFsBSmsYX0QCWyg7VKz+BmVGLsqCgTVyCkQaeKSfr9tk/DVnL+JwajlS29XhdGEilkAmNLp+35zmP\n5xpoepR1K1Ywn2MO5XwrIpJhfja/aWjugWcY5869y1YSdeFdPLchARegQDECtSK9rAWF0fs3zT4h\nqLF8vtHmu+Azi1RAh4oXL+nvhO61Jcn3Pt9PXI8g+/Dhw4cPHz58+PDhxNkgyEkoveWGpI3y7+24\nZZGUuKuoGRHdaKS/+DuLKFSiUUj9tFFIDULcoymgnAmNQmhm4RqFAGXGYU5WIYt2jCImyIz1523b\njteBVHdgo4t+sJiNZiaNHVsMOHCkVUREagcws6A8WhVyZYf2PCGkxWIU8NGcgwh2BHm0tOYUHfKz\nAU1E9P9RU7ep7aJ/TlsoZdZZgmkJDFxIqM9w/OTIyqJxJdhf1HHi2FaB/PeWQdgvTpsgNE909dtd\n15Vujf2D4cXJBYui11E0ecoo5NginyIiYc3pEdDS7jokXobaBh51uAg5s327Ws0akE6DLTWLQIkK\nE0FuX7JofSvm2JZNZU5W9f8GshvJsWOZDPMSGqvwesVdILAY+2bPrr4H53Q135+DUQgQ6xjFF8Ml\nHce4ac8TArXMaYqBbXMg8SELNxxRdxqD0AKehRS09jSFd47oOpHjHO9VHh2UtiHS27zvFN7RgATn\nZqFggjalAdp6aCUPp++kpfPweuQ7ZWOSwik6ZGGdQNpOKCnEYwAVrm66RR5lpCFkESALfGlBPrL3\nX5Hh+4exZlGOKycpIhJtWdlHjnF41Pnc0kI+fPj4tzcCGIHII/3+V/Ddp9RmHfN5+MSaNpki/jrm\ndGS75BFso3EMU7wnIiGQ4wyo8vQvkSlDtjXFfDv3sZ2XKLNGqcoQc9c0nu80JCmcjGbjnZXSeWiU\nFG2oYUeOec9k0sTOhbVbepy8BRnTk3JB9tQdO39nbTwfWGwNdJhF0cykZj2b2WamOcRYc3xoVMKo\n37D9ofhBbatTMpH7LOERZB8+fPjw4cOHDx8+nDgTBDnsDKX507sG1TLhSGyQW1MDB5Crreaq8hLD\nI/A/Hak4Y70Ma9wK+JZG0gwrkcLhxVYo7g9u4yQsHosHMApBm+oty21sXlLOSvLhXX1jCVxJCHTX\nV2G+8MhaIDZnZ9AxIIdAmxrsH1eKeF9EpICkC6VKEhockE8K+ZPKwOFuw8JWxiSmOLa0oXTHoHpb\nV1B1GCsYKS2sOIfffUVERMK6vfy9xTLyPmzSWlrHcwBkvHbk8L3BEae0Xm8e8ld9XR0TXaUhhohI\nNKSZCNBzGpMI5fnQh5FFt4dz+nd/Oiq1IWvqPkTci3mLVDOrkBOxptX5MoXGwYF36KLt8+BMD2n9\nrMcYzGH1DR5zw+GOj5DxCEf6yoxIE8DACEYh5HaLWL5UjuEfIjMSH2p/js9pO6ZuO0Yh5AbDQGO0\noq/JQ71HiVqmL10y+3SX9TgTfwCjEJw3WgdiABOO6Opl2zZyuoBSUAS/8mPtEAXij9fsWLceweQD\nK/futaVS36fC0+vwo0vaefM9Qr/4/Y8oAXTPMQoBt2x4Xfl10V+8q6+T+M6RU+0g7/EFcOPCsjQS\nX82YPP+cbRyQYdqnWs4xXnEfdK5bI4DqH6pQfpwkBoHx4cPHsxdG9mxd56P28/q7ZOoTZPdQv7P/\n7Ytmn6PLOv9c+O/VUIimRsWXYIrx/g39/5uv2hP1YGKE30bbr+o8N/9P74uISARDjYPn7XN84oba\nThfIoG5+XX8DDDCVnU/UJMyVhe28rohtDJOR4UX9/TNqIDs60Pk2/GDD7MNnxvZv6hw4+w/e1Pcx\nRzNjN5y2bWu+dl3PjQxzABM1/nbi773im6+YfeI7+psrg1lJkOprhDGmsdyj37R1Tkv/w491m9oV\nk5n8rOERZB8+fPjw4cOHDx8+nDgbDnIlkfzisuRYGRihfOfHe3yo/JXhvCK3EVZHJxcU0ase6Gvm\nmEqQA1pnlSNVJvB/1FaUK0gdVHMWledAs3vg1LaI/pDnOWsRsIMXFN1baMO6cRVcWigQdC7p/00H\nOewvT5TaWAWfZggUkzzW2rZjf9wBCkiTB9hI0/SD4xc4NsspUFJydsdVMhIg1aEj0F2gLYNFjDXQ\n03hX20aetCswngOYpiVlCMC6AB0oxXD1xfKjiYBSXSStQQ2kVuZWDycdu8k+FAiiorQP+dkFkfGK\nw8MOym0YoLFVIOCjFra19C1jYR3jmrHSmMY0Ba7bYMa2rbav740myNeiJbR+HvXBUXZ48taqmtbc\n6HOL+57uTx88edp3RwMgyjB2KbBpOmHh7QSVv9mmIrkJuLkZq4aRhUicTELrGJbSNNJA9iHHMQyn\nFrxfETEVxvmBHrd2G1xq2oEiYzFx0ypFGFMPKFzUyQGjQQnURQqHXzf7S0UCMtifc3SM+Q+40FnX\n8t7Iw67eUYQ3A/eZ3DZG/GjX/E1eNFHgU5xn9DPMnTkE7QyZeaGIvzEDQSbhpp0+aVqSHxyKpKeV\nXnz48PFsRDGBepxbiuROdxQ1LR5qlpp84hlnHqjtQ32IGTo8W8Ibeows1feTjSf2PFDwyR4rijr/\nrj6IqG4R3ldVosV37FzMzF8IbvM8kGQ+D6N93Td35vypH31Jt9nSfUz1D1Fu9DfDXCliM3zz7yBb\nN8Z95vw68bHzbNlRTnaADFtKVSLOvXiOJM64GdUNKocQEcZcHGIuXnTUqAJm5je3rXnLZwyPIPvw\n4cOHDx8+fPjw4cQZWU0rsmlQMjoqp44dbULOKdDLrIwy8n2udEQcbTsiUTgGEcUQyGvgcp25DbWN\noSZh9GifhlBiFIxNNN2W2WZWgFYcxIg2yyGPV0aBqTbB9ohYLWhyGU1/xvolids2HCcH8omVZ0YE\nmZxtZ9XFdnIsgxTHB9IbgeIcjhztwD51qamoAcWNHipaifwO7T4hTknOFY8RDbDyRDeigctB5jYY\nAygchAMj+KwvQ9ufqA/r5UH5GAF4xhFfBxYS57i5x9FjUdu4KI2F9hWoYkJeMfcpfx4P7BjQWjoy\n2/K45Bk/pT/D8jZEkMfH0VVnGedSGfSXfFdWJzsr5oA227RoJyLAplBb27UH5XGIRPM7iOtkbJjd\nwP5sU9gvo7QChYjiaeoOQA+MWgX5ymNVyu7xjfYl54VRWQFFHM7zU9vrBvvrqmXQjp7t57jx84zq\nOc64YXwkSUQG3mvah49nNoxdPZ4lrC3i+8hsBU4tETWRAypecC7jK+dXV8GB2yKTZXT5Y7yPbJir\nLMV5jPvEUHEKcuDCQGJdZDXA7sb6mW3A82Hco0DEZuJC6u4TtWXGj7/JYue3jNO3pwbnYidraJ4P\nY7bU7DGzolHXeQawTquSeKtpHz58+PDhw4cPHz7OMs4EQc6roZycrxs0zSC8jtNUbV9P1VkGV7Kr\nq6CjS1BH2AfP2OF3kiMbd5RjM660UD0CP9dBqntzZWS6s6qvlTbULIBQdhfsyqaNAvbGdhNtJJ+0\niTbCWS1vmn24Dds4kWBfqBik4J6mDqe6cgz3O2hCjyaI9BJyx4YOWEgFCMNTJWBMZDyCZm7HUX2Y\n1vMYDegT6PhCd5ltJ/9X26CvvQXo+PaCUlv6eD9IT+tUTywo/4juaNEgKfWru+Su4rgN2lDn+cfc\nx3LbH3Kae4vg96JtSVcbzTGvJW5/cN2haW2yAET+gYx2V+1gBynahMscDqkNTeQTx4rtNR1Mo01d\nZCxMf3AfgDfd2LH94XXhuBDhj/q6cZ+86MJqQVd2wGEDTyynTjBW1OTu5keOjibReWpuYmWdQQc5\nbKKjDm+ZDkgCbjBVUugulxM13bPqLFRaKcAFNnqZ5JgBUSlGVge59kjbmYX4HpITTPcoqFtQjcb9\nm25+4Qw41nRLxHfbKFSIGIR9XMPY8NTyMjKvBz6tD+2+H4RlTWoRkZCKMZ2yDqgPHz6erRic17kp\nvnlH3+Dci6wXHWTzbTsXJEQyocRFp9f0gTp40oVUnIxXPo06p0eYd8ArDuguB2WwygPLDZZpuA4/\nUeWvGM5z4S7meLio5luW6zx9Cwg1kGnOidmRztfxmtZmmTlTrOue0aRfUzWLAPUbZt52nhPMyBHd\nNsfic2iMXyxitfzzsXmV7xcCx9/Htu4kgApZcdgu/Zb6LOERZB8+fPjw4cOHDx8+nPA/kH348OHD\nhw8fPnz4cOJsivRyLTiiVBgR8qTjpK9Jl0ChE+XRKsi6hiwccxycWTzHfWnckCGVTnJ64KRJKU9G\n2kWYsliOhVdFaTsRkep+Oe1e3y0XfdX2w9L5REQSJ4srYukGtMzm8SOnEI5tIM2DY2CKsnC+tGkH\noXLMIjmkdWmswRMGtKJ20uTFWBtAzyC9YO4jWAG3HXtdWk0vaDo+7ujxKnuaLq/vWWMVuxMk7u5q\nemM+0NRGhaklUBGSTsvsUtsZlNqbUYy8XU67RId2gFmYGGRqWkH7yNoDvXkqB9q25MAWAdBEJDqB\nRTIk1AKcl2OUVWbMPq17uv8IFuksiqjtw3hlFzI0J/bmockHCwV5bVlYyELJxk2bAooGmk5r7MDC\n/KGOcbyr6am4q+n6sGfPEyBVFc2gvTiPoUcs6tgEO469KegFAakIu6BWwMKUaTBXvqfYciw7xdqq\nBpBqY2ouvbxitgnf/kS3YdoLhSAh2pTee6D/N6y04vEL2qbmp/h+ojAjAlXB0EBa9t6hzWg0r9bm\ntGsl/SOARF1xftn25/1PSn1lG0xB4aJeC6Y63X6EMP1h24zhDueWqqXAGJOk9RWRjTG6kA8fPp6Z\nqN6HtOa6mnIYyTHMKaPLOv8kG85cigK+bA3PsHs6j3IuI30h3XtsdglvsQoe1L9r50VEJN6HqRoo\nbEdftoZFk/9CTaHMPHcIM46L2tb8g0/1vNPWWOPh1/Tc5/4SNEE8D2gKlT6EodT8vNkn29XnGY2Y\n0pbOxRHOG4BK0nl51exT/d7b2jb0NcD8aoq8QdPIPvylHQMcL8KzJG/Davqk/AOMtBMRkQLF2+n1\nC1K8V5HPEx5B9uHDhw8fPnz48OHDiTOTeSsCRy4EbxcOGkx01gCf2IhFZ0Lwz6nnCriAIrk7dD4U\nEcm53WkmNs/DxoSUBnsKaZsFakSqWVhHtNt87iiG0SSDxzNGF+hz/pSFi0GvaaGNRuZGeu60gUeG\n44SUe4vHUOiUcmnOibi/0ULBC9rYXdJBrzqSekS3WbyYdCE7E6P4cCk+1TZGbatZOm6QQzQcx+8u\nOuuwAHbORMvr+lml6tws4oiVi0hRZVEb0GZK0HX1vH2YwRRO8VxaRz8qlBdEocNY1qG75EjQDfQ4\nLIzkNWWhJ80gqsdOkd4k7hXI4LFQNemwCFFfq/sWCe3P6Th1UdQYDnX1Wwcy3lvW1XjlyCLI0QEK\nP2gMAsTSIKFoW0kmiMVzJ45sjojkKKILa7yx7c3DFbtBlQ91xV6MGWwQ7RYRKViUwgIN/F90gCTT\nfMRpW217UGo/U0c59iGiUpJfoywdLOa5DQsHeW2jPWscYr4KtKE2MkQYPxqJOKmrAqL9LII5JSPH\ncM15+MdBu1T06MOHj2cr8gmdz4IHivYGFRSSYY5MkFlyi4WJlkZ7mE95LCC8JlPmzEMs/E0f6XmS\nLc0iMkNHCbTmA2fOx3GyHS2ei5qa1Q3bOu8FNB9p27a17uM3BOXkxouhJyBw4Bg9mfkTfYxgesb5\nlXNx477NPGcsxEYxo3kWo3ic2U9m8HRbzP/IKI4bPTH4THCPmzw+kGD4+eZijyD78OHDhw8fPnz4\n8OHEmSDIUS+VyQ/3LC+SSI8j2B8eKFJTnddVUdDRX/yVQ+UAVvb0/9yxDAxhnBA+UC5PZU55ixTq\nD4A2uYhNFSsk8lAmHupqr3IT3B6sjupTdmUT9/W4Ex+oVWTlvPJdKg911RL39P/aLcspqi3pPsZw\nYksRtzr6l7YU3Uq2rLRVcExESpGnCnlClDjDytMV5s4nwenBWBiUFGMbbILb6vCwm4/BmX2sq9Zg\nCJRuV1eE7QtXtM0je316c2UENG2Aj5TAFnmOcnmnTTLI76XMW9LTMR7AAtq1mqa8WwQJtcxwqvES\ncju7ihzMoA2zaAOGlFbMowblBS33kxKDKaD+GJzg3kJZGjCtmV3kZI1yfvp/DLBxMFvOYLj3NW2p\nuQ9l8tgRfj5q2f4Q7acU3WCKKLO2lTJwU47xCY1gQsqwLYNzvKn3pEFVL583u/TX9fonfwLuF+yb\no1m9d8nzJY9MRKSAsDutRIsl5cjlH4G7BjmibMZKHsZ9IA84/ujaOo6l/aveAzJwbKV6OsuwgIfE\nTwhpHsoc0YY9v71h9uG5i3XlqqXvfazHJdpMiSRHnD5e1m2NxBAQYyM4T0H9i3YMcli7EoE3CDtQ\nkwDHH12y3L/gzQ+0H/W6NRLw4cPHMxchnqcB+MPD59RqunJDfz8UyDwNv3LF7HPwvM5R87//Ez0G\nUNloXTm66X3l+QavXjP7pMicRpireld1jkz+9B0RsfP20ap9iLW6+lyIWzqv7v6G1oow4z37EWRh\nd2yWrX1R57VZzK/5JfCGB/o7JZ3S31DRzz42+8TnldPcua5zYPWP3i71yxiWOOZq0fPQ0+X8uK02\n1AYVJjL+2gt2n5tqxU0EPgzGfmOi/uTwNcuPbv3Tt3TfqcnPnc3zCLIPHz58+PDhw4cPH06cCYJc\nhIHkjapRLSBC5vJ9i4Gucoy6AFYAVGwgYpjVHWvmTJtX26vjs3J1eEgOi2OznE8ATYJdM1UGEqyo\nuPJIJ+2qizzRggLc4AITxcpq5c+1H+TbgleMz9g/9iNuOhAl+wXEraijrbSLjk+fx6gvALUsEr6C\nY0uUy7G1ZLuJYkc9oLY4LlUzaCMtIlJpA+kEsE6+dRUqGuQTc18RRzGkR3UHcoPJi6aJhr2mVPmg\n6kOQhaV9yJeOOpbfmURUw0CfwQ2Puin6gfdPnNUizk1TlgBZh+QE5wV3O+7brwDRcaLYZpzAJ660\ny33Qzpe3pboJ22iO1bWB58UrAAAgAElEQVT9iSaj8j5UPoFqBdtB5RIRMZak5AKHbUUpMiLHyIwE\nbYvSVqCSUdD4gnxfrtQNqmq5ZQGyGBlVJZDNYEvIyw37Dv+WKg9oS7KHTAkt1Jk5ccTeeb1ztp9c\n4Jy222X7ahGLzIRHOB551xSeJy/NnQ+Oy9XOxugkL1eIGy6yODaqzBSMIcIFOHOxo+ySBR5r8OHj\nCxFUXYCSQrKjvy04N9IiuuIYhbQayE7SJpqKOJx7MR9F246iEH+PHFKtCagsPqdRUXJiM1kh1J84\nn7UeQqUHZlusHSkOrIFH5RgKF2hLtI3P+MzEXJ85xklUx6htI0vNehCqS7AeZOjIhaF+hnM8537W\neBjb6G3bthRc6YjzKxFhshXwDGg+tjU+wXit2ucIP6v78OHDhw8fPnz48OHEmSDIQSFqdQukJSA/\nxFEVCMAPJHJHXiy5m3yf9r76N1YLRIS4Lc9DzqGD8JCrS44u9WiDHlY/WN2Fw7L1rIgY/mMOlJbn\nJRLqVq0b7WVwXQNW0mdj/MPUaRuRY1aLgidNzmSOFZSrf2v0HMaWMuY8TpvMZ+gHtYaNygdQ5v4s\nLZPtWJNjnI0B3hnQdPP5sWPnjKaNZnWlSytoorLDFrSVLT1IghyakUPYHlepU62fW41o25DBjB6P\n/F6rFFEp9adkU47bIKlRl1jHoDePlXwWoV8Op5qW33gr6YAjvAQrUaL3JQ4y9k2oIy2lGGEMBtvW\nprM/xXOTvwyE+kj73F2m3bf9etZgERqgApjoQtDmRRiV3hcRGc7p8RKgE0FdkQ6qTAgtmmFPKmKz\nGiFQZnL5iQiELVq2O99t6lkCqR4t0MIaCPks6g4K57tBO3pmQGawDb6nxTS0mnf3Tp0nb0HvmNmb\nMTULl3cWQo+z4JxBRDq3WQ0REQEvW0QkJKrNzA6+l0QriNanM1bX2dhcZ5nhO/vw4ePZi3xa57cI\nmbER5oF4R+fbAnN0Omvnh5NVKCABLWU9RUDdYKDP2cqs2Sed0Lm9ChR1iPosZs7DOdXEd9W9UtRG\nxZifj89BcxhzZbKqn1ecOZJZTqOasaLHjdraj8GyzqHJPfsMkwXwr2ehuEQ1JXKQqVjkZt/m0Tec\nm3Ox+R2EbUerdgxi9D3A84+/lcxzCa+9JVvjM4H5uhgOT6ld/HXDI8g+fPjw4cOHDx8+fDhxNjrI\niLyKw2FFE3YdXizdrqh/DOWGqFfmlLioZlbTVUGCVYJBh8nVxecu55C8R+NcAy5wTkQKq5fcqa6k\nW10B/mV1p1tqU+UI6FzNrqCC4RgvEbxf447XIUHXbpNDOSNghSeRKa4Ij3Bex6GLYxgMwEHFWOQN\ncJmIJB65urS6ws1QBRsDLS8mdLW69FPlJ4XHjlpGQ/uWYdVqOLpHcJebg9rAwOGEghsc31CntNW+\nVtUavUagkVyBilhnPqPKgetAVROjGHBgOaENjG3zkULRETjP0aaqIzTnUOF6Yvtj3PeYOcBx67jv\niMBXDxfNPlUoqTDzwQzGxGPtexUcsPjQcrE4XmwTuenxkW6T4Told7bMPvV5XaFP3tfrYbhqT1SR\nZO1Yq4ijXTsG2UOtkI6IGhARhXKELAGmdxVdcNxgQWFtuh8ZtyPcf/nmE7OP4fyS8zWJCmY4+JHT\n21+5bM8Dt7oIGpyVe4r6joBEUImCznQiIsdrqC8g0oD+BQvaj+L2Pf0/tt/TbEePGwGRjqBYQy5b\nCGe99IK9psHPVX2DKDO3IV8wWtJt8wfWwcpoSxN9BiJkOIZ0r5x2XP6Y/Tm3KsF976Tnw8ezGsFH\nt0VEpFhTpzk+SwI8X9MrOn9ThUtEpHVfnw/x5Yu6zV2d32LMMURRgxv3zT4xOL+cW/rz+qyZXNPj\n55gPj/7Outln8Y/fxR86j878Qp8hx1f1PNFbn+Bzm+psv6Dz3SqdSj/G75OLep7KWze0bVX7+ye/\nq+2MVjEXL5Sd7ohGt1+yaHDrj6E6BDSY2cOMesvPXdBjfXjH7EPFL1kA4s56FrjCkilQXbXPFqNL\n/eJFKT50UO/PEB5B9uHDhw8fPnz48OHDCf8D2YcPHz58+PDhw4cPJ86OYhEElt7AtxwLaCNlZs6M\nIrrRmFWyQzg3tspMP9CqMMI2TM87VrkmtY60BwnopCSEfW7nmFdATovtp2wZKRCkFRSOHXJIi2cc\nxxickC4xLBcL6jY4Hv5nf2RMri5vusWNOA6J7WZ8QLGogTJw4ljlYlzcIkkRkaIOOsATWlZaC+II\nqfrwpFZqC22KExYhOnQW0hZoW5lsqoxLAfkZQUqm6hDlA1oX0/gC94Wxz0TkTttYmJaQpoNiR2OF\nSVOLvqVYsLCKVpWkE/D+YoFX/ZEtaqMdp7lmKHZsYJ8IdJPAsW4244U2hbWy2Qv7R6kebQKoOywy\n3dfPxmV2XOmxgtQg0DN4P0f4bozmITzftxSYHNc/XtB9gjaOB4pCmJfvLW2ntptFJJ1lHZ/mwTSG\nRtt+smanDl5fFtHxuz6c1bFguWXgUCxO4MuxRItV9g90GdlROkg4Y4vnBNc7nVXKS9IFtQbWpCw+\nPF6z13TyU9BJWAyI8QpBIckWOTaWomSssTHWIa53OCbllk7b88QoXhwtT0mxOVYA6MOHj2cmWGQ/\nPK/zw2Aa5mP4fcDCuKRz2lQrOq/zagJ6xHBNj1FhMZsr10rKAygVR5f1+I1NmIHgOXV0zc7fiyiE\nzpdg+oHnxMmKbtvCc4+FeCIir15XusdorlxE113XublxH/Peoq22D7fUyvpoVfs6fYi5EnMwC6kP\nrtq5cOonKLIGNY2/mSI8m08u61zf3D5dmN07j+LCvVppH0Z3yf6+rKHg+uBqU7Kbnw8D9giyDx8+\nfPjw4cOHDx9OnA2CXBQSpPlTJM7sysYgn7A3JvIaAEGmtFY4sscwSDFXV6wfSikaTak1R0qNhHnK\nxsFSmDInRLVDR37NmFaY8wCtjWhaAGkwBwk1RVKUnjNo+ZisiCvzBkTPnKcYaz/P6+xj3iMiDv0y\nM248ryunQum5tDwWRq6OhViuDaORwcpK/0tBQ49yG/XNoLQN+0GZKyPr5RZR8rgGvfwVAuCOdfav\nbBteC7bN3UfK6Cg/CSQqt9Ed62zsuuRjfed5nXEzbaJkDcxtzDZ5+XwiFj032xTlsTbj6H6f+Bnu\nobyCbAQlbZBt4fvue7xOJtNCK+bwKUgnt8FnxgqcqDqK5vLkKfuMSe9QItCYcSR2uslZhxpRY4jZ\nInzXiBC4SAGzApXyuj7gMaLT8oVsL9tUxOVMAsfTHMNtE4uBuU9cni7H26HbhnY8fPjw8cwFs480\nz6I8KIviOWcGzqOS75nfPZgjcmalOb8mzsTKjBXnU9SbMUtu5rRadmofZpFNm5DsCszcbOfVpbpm\nFh8mC6W2sH/jc6j7d1obs35mmzCPl2Rj+VmV8ziMQXC+HFKpgTsGlMBFW0wWPynPxaYdTlvyJDBy\nop81PILsw4cPHz58+PDhw4cTwVmI2rcm14s3vv6fGx4xV0mugHVtW3l8vRXwB08UcTu8osuixq6u\ngtKq/c0ejbRtE7d1hdNfhtEBENLKEfg6Dgo4gnA1Vz+9OV1pzH4AXidWVv15u7TZe1lXLCs/VAmR\n9mVdbrXuKR/z8Hn9f+YTyz3trIN7ilNP3NfPuqu67XBCzz/x2HKKkgMYEAwgCdaC5FS9vNqjhbKI\nyHAavGGg3IaXjTFu3FeekouE5g3dp7dUL+1be6TbPvg9FfmuHNprP5yCLfQkEPaR/l+Dmkp3iTbS\nDt8bi7ilt7Q/W1/TcWzd021HE+CrnrPnqW+DiwWlNK4wK0fYBodvbtlV8WBKx/LgRRiEwBZ76q72\ni/wqWjSLWO55pcOMgb4OJslR18/3Xrf7VHeIGOr/ESjNnRf0Gsbb2r/anh0DjhetugczRWmbETwz\n5j+0/TlZ0evcWdNtm4/Rnzs6jjuv6nkmHtq2zb2rFyL/VCWGQsquHYD3DTQ6XrISZ9kKJNPeU3md\niEYbkEUj4h7NWymeYgY84o2HIiISgFubPdnW84IzTBkfEZEC0nnFY8jFXVW5HpoBkctdQMpNRKR4\n+apu84uberx5vSdz8K6DZUjT3bpr9olmwRcmR3gffadtK+XZWo7tKO2o8RmtUI3lK4T743NWKinb\n3imND9FlY7BCVNsxF2Hf825Xfpp/X9rF/q8FRn7jjTeKt99++9dxah8+vhDxt37nvxERkcqPPxIR\nkXBV5d6yRzq/FTTqgmyZiEj3eZ3fqn+kMmzxks5vlI40NUbnVs0+Q0iXVX6uc36A+S+9s6HHx5xZ\nrFrJthw1SdFNnb+737giIiIJflNQnjb+yM6rx7/zooiItL4PCbhzK/q6rc8cI1v31kdmn2hNt6F0\nrDzW5wNrhzgns5ZFxEqSslYoQ62S4S1j3/CVa2Yfua0SsqZOi2ZNNA4B2jxanzO7UHY2OziSn2Z/\n8rnmYo8g+/Dhw4cPHz58+PDhxNlwkEORtB7JqFn+vV05tqjZcAbIbo38EHoL4/OJ03bBREtrqFwk\naprVifShonHgoI3TVLzQ//uzuk/3HJAvcHcH044iBdBMVt1X27pN2kSV5QDo45wVnSY6XuAw/QWg\nweDRhGjSqGmHeNRUNI7oueFKUiUBpimjScvBMdxpIKCCMSDnZrAAs4k9q+AwmNV29me0cTWISgyW\n9fxEyqNja3jBpdIQNsFEseM9RdxGS1aBwA4C0NNbunI+f7ik++5CEYAC5xcs0lbZgRIEjUJon+mY\nloiIBFDGELHWka0Hi9hXr0/yWBHE1hxE0A86Zp8c5iJhB5bJMC2hNTfHteYYhRCNN2Yp4AD3buqx\nahjjqGPtvdOWbhsOqZqC6w/lE/KsKne37XnWYNN5S9tUe6R9DWGOUn+s4xX0bPZBIIwe0qIUvC0i\nycUSVtC7B2aXaEurgYsrl/QVKGfYsBaoIiLpljUKkSeKnhoOMKqhY4ivZ5tqeNL/2vNml/gv3tPj\nEmG9o+iFrOr9QBQ4mrT30P41vRdn3sN37eEj3QYIeHZTxeIjB6nOgBjHUKkIcHzZBLpNq9SrFg0O\nfvqhfgZlDaLQBdRNIiA2RGW0H8gOQe2joA2sc0+KiMQ1m4Ui0i6Xzklw6y/Fhw8fz2bUbup8WawD\nRcVcGQFJ7j0HQ6t7di5u3NK/069/SfcByumaJ4mIpDdum7/jO8hygW/bv6LHrU7gt8anOq/uOnPx\n/D96S/9AFq3xls6jo2sqGxS8+b5+7mQat76ObPf38Mz6WI1BouculvaJVpZtO+/rHB9d13NnmHOJ\nXAcrOjcffnXF7NP65+9on/H8iYlCwywqeOk5Pf9bvzD7MBsY0AjrUJ+R2R7GFrU5cct5psFMa/T6\nJSl+8vnmYo8g+/Dhw4cPHz58+PDhxJkgyOFxXxo/+EQCxyJZRKRwNP3IsanB6pX/T2KFQM7K0yoY\nM1jhEsUiJ5BcH1dVoFK32qQiIpMzQIEMX1HRv3rDbjcDG8PioaJj7EcBrmaDlrMdy0GWatnCkLya\ngHrPrPzsOcgoUefhSJ4aUEmIncp9InnGAhj/N6gfDCQsd87DMW4A1aLGsDmG4Yg6SOgCUFggx9RQ\nzqZ1ZUb0Pjl07Kkr5bblyVhV6gTsfR1b7mCM826403w/Or1mKyYV1aYKR9xFu4Hwhn3qVNt7h8ix\nUdCgtiKvNfZNnCzHCFkOaglHHXBbA1gYgyvuIsjsW3Sk4zJc0rbGtCdnfxxlg2gfutHUqcYL74vR\ntJ6vemC1eTNyc7+kK/Ye+Pi1h9CVBn+9+9p5s09/Vt+b/XNFGnJe7yvY5hbsQoEwi4jIgWoy01b0\n4EVFs2d+oN+faF0R1+2r9ru+/C5QkBXlwnUv6Heus6LjtQjkNZ+zmYT9l/V1/k+B6MI2erSo92HS\nAnn7yKK25Fcfv7EmIiLN732gbQUKw8rw/qL9brYuKnJCW3pjPT4q3zOlMYCdaQ5uXzjQdsddWpHr\nuB6+blGY1v/9cz3+suXC+fDh49kL1ij0f/sVERE5uqRzyMynOrdkdZ0fNn/XIq7dVX2+PfePgD7j\nt0T3a4qaNn4G++pvvmL2iZEhLZAN3fyWzmGX/jGeS9eVX7z3NVuztPRHOicNntdz772k+x5d1efU\ntT2t/eifs5m5735HedF3/ldFgQv8Fti/qPtOzaOmY9vq8nO+ZD3Tuf9FM3WyCF405uL2RftbpvW6\ncp2HEzpe8TG8Ax7oa9qEV8U3XzX7hE/0eXRyTefipKPPi7gNO2w8Xze+a+tOLvy32p/8yuznhoA9\nguzDhw8fPnz48OHDhxNngiBnk3U5+c51GTXLxYKVY4schkNdQQ2noHOKj/ozZVWDUcPhIAMQnP9Q\nVw9pA4gydAejPhUX7HnGOcjt87oGmL4DfuwAvNI52/Xegh5v+jbQLKx+qP7Abd3+mHbS1O8EXMoa\ntVj1/aR7WiUkOYFrWFQ+RgwO8nDy9GWh21+ehNhGX6uHQOZ3LLLbhXpFd5EcZCDTXaCmUP+IHeWL\n+FAR18GSInnxCapQgXYWCfidExY55BizspS8W2oDk1ecz7hiiNy37IpoNHrz0+MVAEUMZhXNzuiK\neEDtXyC7hxZtzJs6BgZJxsqWjndErNOmXeFaDrIikFkT/GKopsQnRK5tG3k9ZIroM7jVRLOp5OIg\n5xlW5KMWVtJH5exDso9K4JpFQsk1Dp4oF7mxA2I5HeiAXDbeu2/7g9eCznl0K3wEPjS4YK5SBHU0\nqZc59UsgDchKZFCimL7jqGUA3Q6RBarfUz5xAxy9FLzlqGfdEmc+ggoHHAZz8KArbf2ekhftVkGn\nu+qu13obyhQXwDXeZH/0mlf3bOYqA1cuQPZJmkCmeV2QSXDHgBy5aAuZKqA9GSu0cY9O9xwOP6vS\nxYcPH89ykGvcuHuIV3yA5173qs7FK3/65NS+wzXNRlWRpWp+gm2QpQ7e/MBsm0Fph+o5Sz/VuTif\ngjvox8ovnnnXIq7Zts6RlYHOTSsf6Fw1f12zxtknqhpUb1u1jO/94HUREbm6qSoVAeo/Zncu6z7k\nRV84Z8+zoRzq9T/UeXX0qiLhyQ2d+2VK+zPxyJkR3/tU2zYBNTJk95ld5e84w5MWkQLPveZN/CYC\nB5nPDdYSXTy5aPe5Yv/+vOERZB8+fPjw4cOHDx8+nPA/kH348OHDhw8fPnz4cOJMKBZRdyiT7z6W\nYqxIL3BTkCjkaiD1TQmtbFpT+iHMM/KqW6QHKasNTdHWmHKm9SuKjkzxmYg0mmUJq+ZDhfEpCcbi\nnMaE3Y6FQZUNGATQxhBFho1ppD9ObJGem/4WEQlYwMP24xh8X/9BkR4K6ijVRWtHFmlV3XEk9WCE\n9D6NDyBbxjYZwXERmXis7W2OtxvHZ7GUe33ySUivnDiFlSIibEtRnPqchXymQJEsAhZNsgCq71gz\nj6h/B1MHvs8CMo7R0J6HElpMp0QnaDeuT9h17jNEiBQWtxGOAa87CiIpuSciktdB3RhCtL0HSTjK\n+5EO4hSFsqAvxLik05SXQ5sKFHw6BZERpPOSAIUFSM0VHW1zsaopunDfFumRXhBf1AK7bFbHJNpF\n8R5MObK1ebtPS9td+QjC6e12+RiPQH2A9JmIvY9ISaCMYO0hJOLw/e3P2KmjgsLREGnCHNJw3VVN\npdUfICXoGHh0l3Us5yiRRNF70EEiXDd33EIUDo7OQUbpg1v4AHcR7kPXbjuhTBC+r7Q6Z1FrRFF/\nh8rB7ydpJUZSj7QMtHl4ecnsE72p0kRhq1Gi0/jw4ePZiuwBaASvqaFFb0Xnt8YDnddJley8YAt2\ne3M6Zyz8K6WopTBeCl67rq+QbIvPW4nKHEYaNNg4PqdzbvNjpRcIipO7K5aWSgEDSp11n9PXg6v6\nbFv7ENS2GSsv17gCugIofmzDYE3n4mpXi6IL57dMBJrE4Uv6W2L6+zfQADwj8fxNa5aKF4GGVuAZ\nwt8A+TFkTvs610fra2YfQ2+bgukZJXE55+P30N6X7fw9889UdjSZe9GYyn3W8AiyDx8+fPjw4cOH\nDx9OnI3V9NR68eXf+C+MaUYRBKe2qe4potZb1tVQ0tFV1uFlXbXU98pFbiLWHnjqpq4w+otlCbcK\npLQMKikigzmIaFdgELKgjZr7gMVmMK+Ytyjt3nVdhaz+WIuI2uf1GK2H2mbaYc/csCuok1UguLSa\nfqifdZf1fWM1vWkRsKRNxFNfaTWd1bRNLPhyZdFGk0DnYFZSwFwkQ/9ocU37ahFbZNZd0ePHPVhN\nb+q2m7+FlaFjNU1baChaSYTD1XYL9KtcTCliTVIW39Y3t7+i52090POxkPH4gr0f6qhJoPlKBmOY\nKgoJee80tm1/RhN6ov1r+vr/tfclPZYlaVbfHd7ss3u4e3iEh0fGUJFjZXZlVjUl1DQCBE0LqcSC\nDUvWLOAXsGOFkFixZtEsEJQKtVAXVLWgh+rKysqsHCKHisyYIzwmn/3N792BxXeOmV3PRKgyXd1N\n8J3N8/f8ml0ze/fZvXbs+86pgRyev6MrUFo3N46C5DmME5MnmRQ4bVetpnd+y7et/RRjS8IYX3f3\nqh7ceIbz7PsxmGAhXkN+4BQkaYMbFvCPWLnu+9M9r9cbx7TzSNs2d1evi71XtQGdx/46WPhAGWQm\nTCRgRvMurMbJ4mJlLyIiq8q0Frfv6f+YlEeW+CvKMHGCyW0Uas8PwWaAWSbjqx9i3JBYF0Najcma\nZMjz0JDk9Wv6+qEmblAwnwx2ckbbTgORsC1OThLsMseAzG1oNc3dDEpC0lraWVDj/yGDTAtU1z2w\nFixDBjm02y6OIbc3HMrb2X+X48Kspg2G5xF/93f/tYiIxD/ThLoU82yGBLnI7Yr5OWV6SRP7kvd+\nrcdwviNLDOY3Duch7CTKRzDu4Jz4SHf+Yu5wbQWMK5nVm3e1/jdUFjSCmVqMncbic5+UPPy9N0RE\npPU/YAiyvlpt2wVN6MthICLi58sI9w7uuuU7kFMtMK+e8TbYjCIokUBIa2lKinLXOA2TAbHLSUMQ\nN/dSZpe7/Wt+55SSrsVRV96e/liOiz2zmjYYDAaDwWAwGE4DpxKDXNQj6W2kUtLwwAWWBsfUdLXT\nOwfr3WM9qAfPArKoWUASJ2OwgF1lvvpgCqml1ITlNJlmEZHBSlUKboQFTOepVpw7ZtmvDQYXlYnq\n39ZVSW+TdtF1vBe02ccd9zbBRCKENc4alf5NHInlY6pbDS2TDPWzCSTppugHTifpyPdnPI8ykMmj\n9B0Z0nSEVWTm20bGtbehr+kQbS0wjuchcRZI6mUdyPCtYKU5glwdVraD84i1HftxKxOwyw+1UYMN\nGHdMYRuOcN/xZhi3jLjkYVQ5bwZmt2STIj9uUxCcw01tw6SHMRlp//pYQNOCXMSzwJNjXDNU9YLi\nHBnkaMvHbg8iMKwdGpBA/m9TV9IH6RzOE9iHL0Car4vrbjZHv3A9z2hd/R1fpo8ws/E5jgtY2bG+\nDtaxWxD7/nSewCr9Bv43qcaKkwmtxOyCNY1gnuNkdcDSxjDncBJo4mObo6c6gGR0/YpdvxfK7IiI\nyGX8QHaUQXFx5JTYO4MY5ye+SPIM8m5sGw1+IBnHOLU4sHOOkV9QIC6NrDPl5bgbVgSGPgmtXBF7\nXOZV1twZsAQGQ3ELscxgOHgtMo6ZLEZlrHGerD8QsRBkg+G5xfELOict/DnmFMpnlpxj8Hbkt1ud\nBCqN0WgotKfbkfHKifhcERmc079n7uicXMDsjPG/zqzs6a4rM35Tpdka92Akht2vFBKooxeUaa3d\nDHZO72EOpLEY8nTKJxonnS1qO2rhzhwN2A6xc7am/UnADnPHLrxPMAaZu3pRDfe9Rd22JgPPfCgR\nkbirbcrR95hmccw1o6lamE+1jvMcHsk3nYyNQTYYDAaDwWAwGAKcCoMshcaUktUkW1cGDDJNNxIw\nkPEUigRgKhmTyhWPHsNXlmWQM+vUP6KAQU4csYZ4xAlFqKsriSQg4CIwkYlrU7V+18bAkITHMAbZ\nHYt+JDQzCc7LdpLxdmMAJvZkXZX6JtXzUdGBddIARUSkqFdZZ5blOKYDss/BgID1ywb8PqrHJH0w\nb6FLNlenMDFJwFSnQzqIIHZz4FUFksGJWGaastBDgqYpAYvOayLpk4HHeVGG/UmGwVjnPIZtwUtR\nfZ0OPFPdHPLa4xjou14fyhToB/sgIpLX2We0FYw721TCeCPsD8eJ4+L6gXFMh/g8MJmJxz7OvgLm\nEMTJ//l/YE8Zs+viuRiXG+QMRKOqfbuzdUddVPBw8bgiIsg+JotNhRrXeqrNhCYwjB2DOks5rR5D\nVZMi99c1j3Ega85j0K8osGqnws3JY5xNPREo4TgVFvS5PBHHzN+e1IMJLjtRn8FgeC5RG3AuwfzA\neZZzJA3ASj93OXMpxOZGmDMLzCWc26Kxn7to7OXmbe5ccZ5lPkWwy5YMMA+hvtBETUQkGVbndxGv\nvOWUpKj8RNUo3BNCtbB4xF07zLm8l0xO3AuSYMeZykRuTua8Wp3XOTZhfW6sXS4JPi845/vzRDxP\nFEsljOFrwBhkg8FgMBgMBoMhwOnoII8KWfi8LwV0cd1De0AYpfsay1g71jiWBBqzCQJMG/vQcQ1U\nLKhh17qlWYn1oyAGRkSSY9CbmV8NNQ60Pralta9xOq07kBXASqN+4ONcyhixPjcP0TY9T+sRLI5z\njS+cueXjaWq9mUobG481Fqd+rOefzujQNp96e11aL3OFU2/ryq+EVTIVNkJVDmd3DG1eKl2UeK09\ngoZhEA9ZRxxTDfE7yUD/l+5qG+fPqQVw4zhQ/4BaRv0QDD/61TxAPO6EzGjA7OLq6dzX73YWFsqz\nD/W7nHYYlO5Xxa0dsM1gtxkr3jgqKoc2n/qYoumcrnCnsLmudaH6cF+PSRG7W+8Gq2KwoukAMdVg\nECewd+b3Nl7w8SQldLYAACAASURBVLfNvbLSBu4SHMV6rcwgGZbHiXi1knqP9cU4BkoeHaqNeLo+\nnuo1WevpiTpP9diZexrzOkZs8Oy2X7GnD6BigbgzKiiUe9UVNGNhRUSKefwW7qsSBFfjjCemLnKy\n6HWQ4wP9LMcqP8G1kt1TLWXGvUUXvV6n7OhvyylDNKH9jOs72kGcXd2z9cMriIWDZWlCNQn0XUaM\nZQvi15EpHZ/ReLf8kapilFmVZUjXvT4xNTZpnc1jC2hOuzYHLEaBOLow/llPCMYDb6Mln6GdUymk\nXpNo9FciYGEwGP4SMPepznclVXXOqupDfHJ37azXAB6tQ0/+OuJ9qcPOXIhn6sGQnvMW0M2HsFXG\nfBS9qPHFxUeqhBHP6Fw5ecmrWDTu6rNSiVjdaQf5TvM63zbv4Tmo7Z9/nn5H6znzwQlteKhwlHhu\nyQc+t8MpT2zp/UE+v6ttG3IrFbvkVy+5MkJVDN4HMMczvpi5MOGzTI58kmRuDtVi9j2xYzc959U/\nYiqFNBsSZcYgGwwGg8FgMBgMp4ZTUrGIpb/Zdrq3ZO+oQSsikoCpGy8ilhWqC4MVfUYfz1L5wD/x\nF2jdSqarg+kslAJqjC9FbGgQZzOmwxcWGt0LiPcsl3Cs/mO47Ls+WtH6+pfmKvWXm7pCHC1iHXHZ\n656SOSRbPp3VTEzq7LKOvBFozEJFogamk/GrJWKW6DhHBQSRIP4W8akFGNcJ2NlmW9m0xp5nKKkX\n3V/TepqHumKrLeqYzzxUVq527FnaNr6z4RrYZzjM1XZ1BdfYQIZrsCCjc16yoyz24udgcp9VNacT\nL+khzR2wc2DE86Z+D2m36oYXH3l1idpTruN0FcwY7vr2EerS+tMDv8It2mDe4WhXgNXsoD+MXZqb\n93q+M/d09ZudYJnjDFrdu7qyDd33JvN039P6Ok8YY43+NcDMbx+4MmUKpzxU03mIVTJc8ZY/Qdz8\nMIjNAjtB9QXGcTkN41U40e16keZoW7OQk0sqFVMi2zli3DeUG/ID37YocGQUEeeOmcLdiBqc2WKQ\nafz5bf2Dsb+37+vn0NPMwI7EgVLEhDsWuL7zXWU+yGZnj+HyN+cZcTLe0UD7HEP/swSTHEEXND/r\nNTFLOlZRPQUMO2PZYrAkjiEXz44wU5puTmRyiARsu4jXKC0XZkVuVx1FDQbDcwTOHdRBx45wBDUG\nOmw6Z14R6Xymc0f2ljrnxbfUUc/l8cCFtKL73q66AtPfIH1ZtY2LG6qJ31/3803t5zQawPz6gR5T\nXNYdv/yW7nQlwU7j8AxyhbALybmQc35+Qx1LkzXPiDvGG2oW09ev6vvP7mpdYNd71/xc3Pxvqr3M\n+0BKZz2qEG2qVnT2wad+DDo611M3mipH+TGMBxADXXs848qU0OGfrs9K+W7V8fg3hTHIBoPBYDAY\nDAZDAHtANhgMBoPBYDAYApxKiEU8LaT1ZCQtGgRwGz7x+/Hcqk/GSoWnPaXVi0Qp9NYekvQagdU0\nwiEaDzS4O15FUDy39o+Q9BZIltRgKlJgazvOdWt15jPdei6RrFPrBdu9M/p3567S9r0XkKT3WLeb\npx19P3On68oMz4H6x6mbD/V/43Uk6c3qedqPfZJecqR/R5BIKWb1vJRZcdvxh2GCGpKyEJJQQiKs\n1o0qY+OkvESkzaS8obaFoRvpUw1JePx7GlhfP/JbM5N5hG4gGiLOtf0NJDkOV7EVFOzA07RkbaJb\nJU+/C4vu+1rvBPbV/fOh1TTDLvR91mSSHh080IdnPjRlPK9lDq/CahpfwzzCS/rr+LwXJFWhntpA\nrwdeS6yL39vea75t3fM4Jy7BFNEYRy/CanpX+9XcDcYN41XHbvsY+W5M5KOF93Lit6f66zq2/Q2E\ntcCcY/6O1rvzBi27/XU934d5xYNHIiKSLOmJ8iOEVMBuubINBqvS8pfXtVvYrnKGGginCJPaylkc\ng/NEAz0vt/7cltczH14QIZGvYHjH1S19j2uS1qHFMy9o39rBBYCtwBTtLpE8l166qOe9c8+VYfhF\nhCTU/B6SD/n7RxJJRfBuQbc9GZLituaAApba3E4UEcmf7qAtuABg2EJ7bxdKsrLgyyCsRHZ2pcyq\noRgGg+H5Qb6s83V8XcMXovM6/3HOTN5BotzlLVeme03nrvaP3tEPMH8LEvJzGIYk37rsymQ4T/oJ\nQhMO9fkh/+SGHrui8/vsXf+MIdde0DY91FCLwd/Q+igH2/itF/W4249ckdn7fKDCvRkhHIIQsui7\nr+l53/3YlUk3tM85EsGTD78QEZGCMmwwCPGBDyKCMkwWz52xFEJNP0K/XrnmipQICaHhCBMgEyRq\nRzCumlzwSXrpu7DmvvtAZBxq2f7mMAbZYDAYDAaDwWAIcCoMcpTlUnty5NhZh4DZjWA726Cw81hX\nEbNM5IKUCNnUCrCSqUPOjYlrEewFQwHrlJJvYH2i6Uzl/BHYs1rAuM7f1XbHe3oernr4nm2MDzyD\n3DohDh7DcrGJeustJAXtB4wVV1cjyFVRziTFGHy55xIfV6VP3BjjNQIjxjpFPMtXZx7hAIxWV9m5\nxV/r+1rPJ4FNFiD91azKotSPtM3NAyT69QNDEhjDNO7qSnBxXoPs29vKvGWQZWt0Aym13aqAOU1N\n0i7dTJBAtufHrT4HO+JCvxnKuTW3Ka0HlnjorwOaObhEN1wXjflW5f9F6te49T4NIvQlxfsoQz8g\nRcfdDhGRaYfW6frZaLlW6ScTLtu3fSJc/Ui/nyZY8+YeZP/uK4uw2FFGt/3Aj0H5WJPNYtqBQg6N\nNstcSZdznnkv6riuIFdGaTMyD2RcK0Ltu76dIiL5mrKk0dOdyufjTS8NV/8FZHUg00MZNGdR+qCa\nRCcicgS71qW/gLQepYxoxQr2tmL6AQmhclPHp7yP74fmQgnOH8grRffBhENaKIYHOeWIEjLMwe/H\nGY7MIgknqwrlR/h/0fEJIGx/srYq0e7p+C8ZDIa/fki+0F2nCCzmBDvb9QFk0ZAQPj3j5+KshcRr\nSLORMU4vIoGaDOnYy1rW7uucW+AZo39F56POHSTv4fP9l30y3+p/RduYEI3bdX9d57/2x2CO5/x9\nb/cNrWfpP8PoBLuGxarO8cme3mfzur+Pl5DPHL+qsnSNjzE3ItEvSnR+H17zu5Otj9E2JH7HmOvz\nQ90FJystPZ9sz3sJpT2d6RTna0QtjBf9c2PM+9yVFyS6/xXPk78BjEE2GAwGg8FgMBgCnJLMWyqj\ni8ve5IOEzsizjWlfn/zHS4yp1f8N1slM6udcaYn4WOaFAnJRiMctEppAQG4llHlD/VxZ9Da0iwui\ncbJkDt1xInK8hbjkrh4zncN7MKCDDV0NtRuezXIrFixxGnNNlK2hHzoWjXnPmjGOOMFYFJA4o8wb\nZcXKul+30PCEVsNkBXPWD+kXxjeLiEyXdeU6XNdzkwWugbksUWdo601ZMgqL0/Y4HtFog22VLyM6\nYedNebSvsEcmgx+FtsMhiiozr22gxS8OSaost9tRCK4Djq2zTm6BiYdhiBvroC5aezIOnqYsMbqR\njstKWX2jL5Ts4xiUJ5eeQX8obees2V1baKWNnZI0iMdvQpgdAvMR4n0d0wqJIXm258rUumCIZxgv\nDzMWxB5HNR2T/MAb4NDMo8AKPcUOSIHzF4h1rh15xtXZi9Jg4wFkHo8hm4gyjDUTEWnt0WZUGZMc\nIvJxB5I/oy/H8bJNyVPE6y1pn8nGRPhthCwMpeFoxU3DkLAt4fn1RGgbGfbxiZ0qmtBs+5jqgqYB\ncfxN3U0NBsNfY0SU2gSLWr+LeZXzXFufI+q3nrkyi7vYycacRSvoYk937Cjplm8/dmX4Gefc9kPM\n29ghznd1/uk8CwyyBkOU0bZ1PsYu79lFnA95IrGf/zrbyBHhfLetEptxf75y/hCcV9tfYA48B4k2\nmFLF2C3kM5qISHZCcpO7em6XEPNqOAbOshrybsyboTQcMfNpEO3MHdIkcXV+XRiDbDAYDAaDwWAw\nBDglFYtcGttHLpaWRiFRwJpFR7qiiYfKKkVDxE6WuqKqHcHQoRE0CWxi8khZsXiALHLWj7ji0Gq6\n1UeMJpnXCeJx72GlwxjXno8Pyhu6Uqo/BBN1Fm16coS6NLaIMaKVfrCNMMtIFxFXA4vodMevvlzM\nNNixhFbTZLW4kgpit8s2TAvGWfVY9m9Hma8yMDGoof54rG2MBxhrxHJPty6i7T4+Z7yg9VJVgoYn\nZDmHMHgJzV8KGqq0tI2jJSgSDPQ97bbHc34VF08Rmz2usrWuv2B0ybaLiGTzqB82zg0MKcd42gG7\nHawWHVNdgjlGtvB0AfbHYG2n/jKQwWr155AO9ZjRMvoZk3n3x9GwhfsRw0Ua0ySV/7dm/U4C465p\nrDOF2Uh6CPOcNYzRyI8BR4kMKIXTHXtLi88Vn807XcU1+rbPPhYRiaECwczg5MyZ4J/V3y7toose\nfr9gL4qa30pw9tCMsafgexv9ohpEcI3yOiOLHYNZichsUDj/UcCo4NyyDOb4sy8wKPheGI+dBwZF\nNBpBvwow8I4lZuzwGW8YQ5bFjTV+l1T/YJxdsebHuoCxSRRFFUUZg8HwnAH3fOZ9ZGBnE9x3mReU\nbflciO6WssFzP1RFCuY5JNj5ozFS+oJXvihTKnHpXDXBbnQNxk5UMsqCvKF4GXMSGOr+axrXO4HJ\n2uKuzs0yCHacKd4ExjraQNww87ig1lPcuO3KJDjPGOoR6Z9/pMdiruQ8G2VBFAEVlnCfLo71Rk6W\nuMQ9Jrlw3pUhm8z8lhjPKe47wBj1r/i5uPFH2s4kSSrPhl8HxiAbDAaDwWAwGAwBToVBniykcv8f\nr0pOGg0LmjgII2wc6hP+AImK6QAauS9As/eAzGvAvoCAXvpQtf1GZ8jk6efUno0nnqmmbWKJno0u\nKKu08KsLlTYP1n2Z5CVdyXQvqBbqaEX/19zRpVX3kq5CZu94rdTBWhl2VdrbylQNV/XzvI06nvkM\n01qPr1WN3ILJoeh6GOebIRk1BfGV49gM9c88UPa7cRyMAey7++eh2HGk52k9W0EbEZd0+OX1UR+L\nt9oxxxortHOI6Y5946hHXe/qCrN3DkxehHhVfAfHV3z90xkoK4xga9lBvOqJtrRbgXUkWOXeBX0d\nTLFKTfX76Z8FS7vj65jMMg5WB4yx7QmuSTL/hy8HaiY3tF5qGVMreXBemdECjOK0E8aiYwdhhM/Q\nhPGSHpuDOK4NfX8Or+ixvM6yOzi2rt/lGEx51vRa3YuRMgvJ25/omDDrGbbIMdmEm3dcmfgeVt3U\n4wQDSs1ep08cKFREm5qVHCGGjTqU6Tn9nNqVyS3P7EZke+9plnL8a13Bx1R9gA1zFmgQz38ArWHE\noTGeL6e6BPrDV/0nNEM/VZ3L6M1X9DxfwCba1eXFumkP7aylERvnbGIde+HLuNg/7FC5ODh8//yl\nlR9+5spQuzM67IoMvipQ32AwPA/Y+129SS7+UFlTeUdVekrucEEXWd7+yJWZ/0Dnnfy7L4mIv//k\n76kCUPy6fl7e8VbT2av63JPu6A56/Zc678mLV3CsznsL7z5xZag6JB9ova0/0927Ju2cL+lzEPXf\nRUQ2f6KsctTG/Qb5LdSMT6Fzz1cRcQx18ifvi4jI8B99V0REOu/c1bqoWLTj9fIZF+1yVbALmkB1\nKKJK2bHfdec8XRxgp5w5RMzJwW5d48e/cmWyv/MdrffRscjhN5uLjUE2GAwGg8FgMBgCnAqDXD/K\nZfPHhz4GlI/dQaYktfSma7oiSLq6iuhf1lVEcxcuMYFSBNUp6veVtcpXEE8I0i9Gln4Yc1jA2YVq\nD+NlXcl0PtMVE+N6ikXP6O3fVAZs5W3Nshxe1FVY64GufvqX9H3nC5+VOtlAfCccamqPdYWTIe5z\nOgs93MeeNYuPGYuJ1dwM2GUqB0DdwGn3ikgOdQzG0FLpgK+1R4iLDsZgATqM2RnEIEPJIUG88tN/\nqKvIesA6jxf0u2vu4jvkv5wiib6S/RbxMciNPcRxjrT9dWglT2a0jfVDHyPFcyZg/WN0tdFFzCsO\npfKGiFcMobNd/QiuQIc6JlkDqgIj3zbGD1OZIoFqygjMLpUpms/89VbgzxoWvbUBFU8Qi5V/eQw4\nQOwX45VPOumF/Zl5iE4WcaW+5o6OY/e8XhftXR8/xd9AgWslQdYw3em4wg5j2KYbyr6WP/tA+ww9\n5ARZ2Bld5DYCZoBKF+wd2BAy04zpLc/6mN1oHy5+iEUurkLbk1/7s6PKeUVEBle0fAvuUzFY5ohx\nfHD0qzjpQbM4uaYMSv6+siQF4otLaFGnZ9ddmZjnpO41MrJdjBxzEoIy+RNkW4OliDmvMUeAv8Hz\nXuMzhwtUVEsruuwGg+H5wuJ17N6BJY3oXncHzxiPoPv+1quuzOG3dG6c+49vi0iQG0Elnutwf7t2\nyZUJ1blERIpX9DxkpumaOrzqc0gaj5Argvn0+Pt6P+BcPHMb/1/2MbtP3tI5cuMT5LNc0N3ClC6q\nK8j9evdTVyY9q3Nf8TdfFxGR1h8pg1swX+OZ7hCGzoAx82PAFDPXo4RCBedXjqeIiNzU3U4qhzDG\nmY569IMYvuTn4uZPP9R66zWnm/x1YQyywWAwGAwGg8EQwB6QDQaDwWAwGAyGAKeTpDefyMO/vyAZ\nHRBB59d83oukPaXpR9gNoPza8KzS7elAA8SzdrCtgB3Npfc1KJ5hAFQnq0HIOhmHCWo4OV6GL2g4\nw9x1rYPb5EymExGZbum27mhZtyyYWJW+qNsUgw09tnXNy7YwOYto7kFOBTsneYNhAH4rI57q3zVs\nx9PWmcls7EfWDsxS+L8h69XXDBEirac66K09357+OpL00O7GAZPyEBSPcIl07Me6/lCPPb6Q4lh9\n336qWxQRMglz7zbpxx0v7WcIiaExSU/PO5nxhepdPYbhEHGHYQZVOZbQZKS9rW0YLUBsveT5ce0g\nQa6557dTGJbB0IoJzF+a+1mlzcnYh1gs3Nb/DZergf2tp9rG9hOEbYyr372INzHpPK6aifDzULKt\nSOtom75vHFf7Pn+32kYRH14UQzKNoRXc5ivP6bVZfH7XlYkfIOEDW30xTT+Q9JFcvigiIhmS9kQC\nuTNKKUKaMHnpqp4HiSGhAHs5rpp7lL+8rmWwjUir1FD+LMV4UL4ng5xP3EGCHITow/APhpEIkgHL\n77+m57mhbYpYdt6HcpSfQZoIoRTcWuQWHWXs8jt+DGiByjI0Z3FSipRh7AbhU9++hhOWEt3wJkQG\ng+H5wmBT54eZQ4QrILSC0psj2Cs3fn7DlZm/rnPk4AffExGR9iO9ocd3kWD31ssiIlK878vEWxAF\nwFyVHOs8NPnbmoQWv6cyl6HhV4zEYhpqtH/4C61iXdvEJDcJwsBcyCDvJZBzK+e1nzGSuKMg/KN8\novef2scaenfwT94SEZGln2vIXIF79XDNixQ0/wRyowiTiDc0rI3W3NlCC/36tSuTIFSE9xuasbB/\nnItbO94ga/j3NOwjKkWKn/1UvgmMQTYYDAaDwWAwGAKcCoOcDkpZ+XDi7I+ZrFfre2aM9rnjJWX2\naMk7fKhNICs3bflndsqdLX6mrFkGQwhaAJOFom21iMh4EcYQYK2Od/V8CzchLZIxmcqbZPQf68pp\n8fPxV9Y/fKx1Ng49Q0m5MoKsadaGFXQdYxAwo2QV0z4MFerV8SJrmrf910KJM46fM5mA8HcDrGlt\nf+DKtCBP135abTfP6xjYbmAXzFXdtFU5Nj1AImRB9vbL7GntriYlzMa6IkyfIegeCWUL8Zw7toFk\nTCYd0hgm6VWthWksoxVq2+bARNNEpL6tgulpD+zqod+yqO3h2J72sdHA980VNPqxMO8THFpPtG21\nLiwwIXJeG+j10dzFOPa8zWVzFufBd1fWaBet40db6do9L6W2kCtLO15UprHFxIpdJLONlyttFxER\nrNiZIBZDWo3sbTTCtTnvxzpmIgNMbCjnRta2fIo6S//7yYOVuIhIBBYj2tc6ciQ95Itegi75SOuJ\nITmXUEJtTce2uHFT/9/xzG7/LIx0YG/KNkQN/ZzGJDQzEfFWqJSci5m8CyaXsnLlih+DMptW+ixg\ngwvIHsXxCo7zjArZiRgMiqvrhL0pWRkRkfIBmKDlRW+XbjAYnjvMvA+JNNyXhLtu2G1z99m1FVeG\ntsqdezpXRbfBOkNaLbmj80ee+WeM4p6XfBMRmX77ooiINB7ofa+AJGZ/zT8vNH4Kq2dIVXKOmlzR\nnbj4Z5rAlgRJepRhXd6HlBrnTCTG5UimS575e0NOs5KXvyUiIgufaFlnnY37Ur7lxRAK3DviDu7F\nMCspuaOZnsNxfp4tdmEStxaYWUlg+AQkL/nk9M6nOpbT88tOTu/rwhhkg8FgMBgMBoMhwKkwyFIq\nI1wmeFqPqnGYImpHra+Q2QLrS0aSzG4SqHKUIF/jCUT+mzRjKCt1hLbEThqFrCzqYwyos4aefLnr\nCcoWsD+OTsisJEFcbNauri1cf5rOFBjnD8cA7YXsWsHhT3wMkYhIHNgzFlzDkLnlEGesE20KLBXZ\nlmR6YmzHZPERI1n4WEmy2WTGC7QpmsI2eha2u8F3yjjvOli/yRzifvuwJwZ7OpkN5P5GVRaYDGt0\nYqGXjPwqkjFK07mqyUgNFtcZVqS1aWDn3KQlJT5Iq2x9VFSl6ERE6nM0FQGbjnGjVTav3RCMbU6H\nMfqDnQPEhbGuesuPdd6C4Qhl8GYgJ9ZlP/W1FsTsxifiYYVC6RRdp6lFKDEGK9QSccsu/oyi8V+x\nGxBTcnAEGTTao9OaFBbNIYsuaa1y7iiBZSnMOVy8bxj3BilA9xkNaMAyOHvncXVnoVIGv2WagJQR\nxiLYGcnZR8SqnTQOichgBwY4ZFBc7DEZDdbF+OvQEp7sSH9oVtMGw/MMyNfSXCgCW0ur5PQAkmRj\n/zBT4h4ZI2654Bw2qJoRSeTvR5SZ5G5a7RhzIQw8WKZ5FOxSY67lPJdgR5H3W7d7GDCwdeQoldNJ\npQ4ew51B3kcq4Lw31DmPRk+cARt7wX0Cu4TMVSkwT3LuTA7QrySQXkU/Iow1y4a7niJSef4pIU+X\n7vcrVtdfB8YgGwwGg8FgMBgMAU6FQY7HmTRv70gJ0WaXAT/1jBEZqPb+bOV/tV7VOMQxf2H99zSm\npEHRfzI4zJoPVg/tPT3GGWkc6/lcDChWLemej41JxirWXb+lBgG1ecTbHsIAYaTxOsmTA1eGx5BV\nYsxsDeYfZROx1odBLC2tFMHOJWD4mKX6lQCjJxxLxD3RolcONd7XMXwiUqNF5KGObYQVVdnTFWDS\nUYthxz6LyATx3QmVLbB0Yoww7b1pvCHiY7VdXG+VCJcCrG3sT+NjmPESs2xRZf4lYDfLelop45h8\nlCUzXwZMPFn6iCtzXivzVamVUJEiB/vvdhncjgFW5V/xNXGHIB0yBp0MOXYU6l9egyZ9xDLPsF9V\nljPHDkY92LHg6p3Wm+USvtsdf02KiMi6j9WaLCEO7T3NjCZDEC9B8YJi7kE8GrOb2WpnNvNY48yp\n8DBa9mx9E9ciFTWKTY1Fny7q+8Y+2ljzaiaDVb2O27TKhuJFhN8PLaELxMWJeKOTYgN9vA5zDrLN\nGMey49vm4qHJilBxg6wwrrcEgv0iIsVRF33V33hJ21SKznN3YMur2lC8X41JLAbZYHhe4YwtEGM8\nPq9zR+Mu5iEcN7rqcxR653TuW/5DNdtgPkVyRU0xilt3RUQkvXDen4j5JXiWOb6ozzazN/Ren6zo\n+bsb/sY0AyUfGiT1X9W5uLeux6xtI1667nOwepcw52Nup6FHvqTzX0J1oEfe0prz6uCatqH5U53/\nXK4H7ufTeX+eDnM2wKaXVNwYwuyMpk3nN1wZqjXJ8mKlX85QCvP60WveuKrzX25hfPyc/nVhDLLB\nYDAYDAaDwRDgVBjksp7IZGtZph0yyPpSPwwDivVpPqNCA1kYxPJGZ5SlyQIVC1oILyLmh4wl41Zd\nTG/AhDJ+kxbQ3Qv6fmZGVyXJQFdLkwXPZk3mwHRe0RWO0+CFLt8UTF885+1oyxRxO1z1jGcq78lm\nxkG2f4EyzHJ1jKtTldBVURaUoY12PEacZS2p9DM5o+et7XimerIKlm9Fj2nugy3LdRXWuI8VW8A6\ntx5j9Uv2HDHAZVdjf2qLUAb4irjVYkdXeZ1fg6U7UOWBGlZ36aFf3cVg5Z0Oo1tNVuObiqBtsqvt\nnRnq98PdhxKf1xxD7lUsqIZAtl7IVO6BkUQM02waxEdD7YHsPMd+aaSr5XQfMWeDQP1jBt8Vd0Qe\n43rG6r+Gumg/KiKSTnU82lCeiJ8hK/lYx6ZzHUzo0I8BR73E91Ci3RHeT9b0NT3wZdzfV9T6Ob5V\n1QtOVpWJLQM9X8dsgCGYLui4NbfAbEAJY7DqmYF6X8clhbJGgv5k8/p7yaFEkW5tujLDM/h9UHsT\n+pZyRq/RAhrOTgdTRHJ830R8CZnLB8roRNA07m55tYzOTfx+GOtOBoKx1lv4TX9809eLYzjW0bH2\nrxjzd4TY/pHfIYthVT25clbKYz82BoPh+cR0Q+fInPk7Z/UZ5+iyzq+dxz7+ln8Pf1v15Fvvqtaw\nY2nlooj4e5pIMG9ibhms6Hlar6t9c/2masf3Lga7oFScAAvcvqN1DKC0kT2C3vy3X3Rl1i5qGWrQ\nl1CiyC7ivv2R6i3Hly64MuWDR5WxKN7U+mqPoWYBLfq9V/xc2H4Hz1V4niou6A5ciljr3muqtNH+\nn5+4MvGijunkrM7FtR3c43nPx65euLNNe+v9N5cle/LNHnGNQTYYDAaDwWAwGAJEX5XJ/puis7xZ\nvvL7/8I7uuAljNnsPFG2pXdOP6zDTe7gRayKnlbd5US8U9vCLV0l9M6C2cNioXkAZYwsdNJTJpTs\n8wjOeqvvYNAsoAAACJBJREFUjVG//n9wxmdK7r2pFZ77Y31/8K0E59X691/S9yvXPWN0tAVWGYui\n+Tvaxu55/Zyuf7P3/cqmtaflqWk8WdD+TMGiZ+h7ve/LjBbBbmMxShdBxgTP355UxkREnB51b4Nx\nxfr57AP9484PlF2t7/v10XQW478M1n+i/2s8RX/O4zzDINs/1TKrf6GfPfu+9mvmDlUa4Ax42TOu\n0bayfDFNyVp6TP0AbcHX334cOB3O6ofHryPuCAzd3E0tMziHOg79tVOgmTWQoxyfKULH+b0Vv+11\ndofb2AVoIH4YDn0XXtLYq/tP4MK263cfigXEbx2DPV8AKwz97XwGLPT7fty6ID6z89qf2n1dQc9p\n6JTsvaH96Wz772ftHcSt/yl0LOe0rdTspbJDGE9Mdz2Bux61JPMnGmtPrcxowesGkwVJP9UyTiGC\nscnMAwjyC4qrygxHn6sbXQnGOtlXZjdfAhP72S1XJj4LZye644HxKB8qwyHXNDZPbtzxZcAmM5OZ\nsXkFGHC2sQzalq6iDHYkyJCzH2RpkqveJUqgD81jGVcXQceZ5+Xuh4i4+OTs8RP5RfnHclzun4jI\n/8vBW2+9Vb777rt/Fac2GP6/wFv/7N+KiMjSH7wnIp6tzZFrQeWddNPHEw9fUha4+fbneswl/O+L\neyLimdJ8zcfNHl/VHbnFP8O8it1Qzn/xku62hfrs/e9dFBGRzts6bw7wvrWt94nhOXgk/OxzV6a4\novN38liZ5OycMscJ5vPB97+FMt7lr7wILXpo9ZfUhAb77FxVAxWi+AW9L0TYlc4x9yfoR/ZEd1nL\n73/blUlv6f2AevjunrU4Xzlv2fYqUVQPyT/74hvPxcYgGwwGg8FgMBgMAewB2WAwGAwGg8FgCHA6\nIRYrm+WLP/iXMp2pMtkMoxARSSYwXUDoQYQt7vESknWwS5D5/DQpsIO58pEePO0gSQ9seoKd+1Cq\na7hEIwh938VO7fwXKINjhyt+bTA6o5/NM0/HSZDBlnoJknFdf56szSQ99BX/y6AIVbqEvK8w1ujC\nkCSthqSkQz02NNYg0hFCIDAmYyQWNg+1rtYznxA5WNft/f46jtnXsrWBvraf6GCnXb/9QUHt4YZu\n3dePcMyubl9PkJDg2ixBqMttTdyabuhWSbqHQHqE3Axe8NtGjV2Ij9MopA1zkeOqIUTc9Ql3NIQY\nX1mtHFPf1m2XbHkG5w2Szeb0Qor7kA+cQWjHMRLXaEX+bZ8ENntTE8UoT0bQlry1A5m0QH5tMg9Z\nt4ymLBgUXDu0nm7c9Tad4y3dwqL5Suuh9jU5QjLYHKXoApMZygXSOpNJjpA4y85jW+yOl+Lhtn9x\nWS08k4c7qBbShEiOyO4/dEVcOAGlBxEuQWvw8rZuu43/1quuTONPP66UpQ1osqnbcNldTQ5MsC0m\nIrL3+9dERGTpR1qWYvi0Rs0eaz9oKy0ikkPyx21pntPvLr6r23BMwBtf9N9p+rOPK32NIZxfTmEG\nsqZ1Fdf99mGysFCpj8mfDLngdxAH0nCCMJVsqSPvfPjv5bi3bSEWBsNziH/wnX+lfxQMxcO9FzK3\nRy/rvDD//jNXhknv3bd0Lp75dK9SB5O9i4/8PMSkOSacD9/SMDDKj9bf0weWJ//0FVdm7Q8w38HC\nmgnYxauauBb96jOt46wXHPj8n2uIxdV/o/W5RL+r+vCU39DPaSstIlLehVU25vjeSzqPzn4Ay+xF\nDQ/Zf92H7y3/pw8rbaNMHu9Toxe0jtpP3nNl0g1N3CuQMB0jIZshF5RGjc6fdWUYJjhYr8v1n/w7\n6e0/sBALg8FgMBgMBoPhNHAqMm/p8VhWf3zHi0/T7GHsg8cZSE5WhqYZXBlQ+DlMfHG2wEjciWAU\nQNaMEh8SWNguYNXFNpxZhRHJtrJPzg531huFuMQkBIS71ReMNQSC0xFWLyIi0g6obvEyZWSqnFRY\nL5Avo5EBpcdoqUibW9onBlaLzvaRFrwMhqeMGROUApm0JsZ4CYwd28DvoLikq9h46FnnbBGmEkgg\nLBqwnIaxBmXraj1fhkYgTvC77pk7EZGiXWVXRbwJB8fCWWDS0AOSfhXryDkweWCk0y6uJVxfCfuR\n+nEjUxzRxhJSXZSxo8lIGiRETpbAOuN/lAQs1mABDRnDRsAg01iF1stjGGg0dvX8eVT/Un/qlKqJ\nkPTF6wLf4fSCrqSdHJ+I5Nt6bSab+t3l68rW07wmAXteXPDi9LQUb/1Ct08yygZdVFY4f6hSPema\nZ+YLXsf4/YxX9Ptv/PILNFnfj+f9WDfwnfE3Vb58UUREepBu7ED2j5asIiKDda2fKYVkjimtlmJM\nHFMg/rc1uazsR/ILFd3nb40mINFmICsIubroxDGsNyFjvuoNVpyFbA1l8Vun3Td/r5OXfRJO8r/e\n13ZfvihR8F0bDIbnCyWTjV+9IiIivcs6T8zc0jmls6339+5rfl7lbu7ZH2nyHBPSojde1gM+BUt7\necufCJKoTArubsLs4w91F0+wGzY6E+zqMoF4WZ9Zur+jLPDxls5Zm9swiVr0zz/1K3iuwfNHcuWi\niIiMz2m/GgUSmJG8LOLnxIM39Z6/8CM1CqGpUoxnguhVzyAzSbxs6TxOudQC0qENPNNEME8RESl3\nkfS3sYwmartj3uvxrPTsdzwjvvQf3hERkZnvveIMu74ujEE2GAwGg8FgMBgCnEoMchRFOyJy75s3\nx2AwGP6fx1ZZlmf+74edPmwuNhgMBodvNBefygOywWAwGAwGg8HwvMBCLAwGg8FgMBgMhgD2gGww\nGAwGg8FgMASwB2SDwWAwGAwGgyGAPSAbDAaDwWAwGAwB7AHZYDAYDAaDwWAIYA/IBoPBYDAYDAZD\nAHtANhgMBoPBYDAYAtgDssFgMBgMBoPBEMAekA0Gg8FgMBgMhgD/G/HkiOj7a73fAAAAAElFTkSu\nQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pl.figure(1, figsize=(10, 10))\n", + "pl.subplot(2, 2, 1)\n", + "pl.scatter(Xs[:, 0], Xs[:, 1], c=ys, marker='+', label='Source samples')\n", + "pl.xticks([])\n", + "pl.yticks([])\n", + "pl.legend(loc=0)\n", + "pl.title('Source samples')\n", + "\n", + "pl.subplot(2, 2, 2)\n", + "pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o', label='Target samples')\n", + "pl.xticks([])\n", + "pl.yticks([])\n", + "pl.legend(loc=0)\n", + "pl.title('Target samples')\n", + "\n", + "pl.subplot(2, 2, 3)\n", + "pl.imshow(ot_sinkhorn_un.cost_, interpolation='nearest')\n", + "pl.xticks([])\n", + "pl.yticks([])\n", + "pl.title('Cost matrix - unsupervised DA')\n", + "\n", + "pl.subplot(2, 2, 4)\n", + "pl.imshow(ot_sinkhorn_semi.cost_, interpolation='nearest')\n", + "pl.xticks([])\n", + "pl.yticks([])\n", + "pl.title('Cost matrix - semisupervised DA')\n", + "\n", + "pl.tight_layout()\n", + "\n", + "# the optimal coupling in the semi-supervised DA case will exhibit \" shape\n", + "# similar\" to the cost matrix, (block diagonal matrix)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Fig 2 : plots optimal couplings for the different methods\n", + "---------------------------------------------------------\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\nrkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pl.figure(2, figsize=(8, 4))\n", + "\n", + "pl.subplot(1, 2, 1)\n", + "pl.imshow(ot_sinkhorn_un.coupling_, interpolation='nearest')\n", + "pl.xticks([])\n", + "pl.yticks([])\n", + "pl.title('Optimal coupling\\nUnsupervised DA')\n", + "\n", + "pl.subplot(1, 2, 2)\n", + "pl.imshow(ot_sinkhorn_semi.coupling_, interpolation='nearest')\n", + "pl.xticks([])\n", + "pl.yticks([])\n", + "pl.title('Optimal coupling\\nSemi-supervised DA')\n", + "\n", + "pl.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Fig 3 : plot transported samples\n", + "--------------------------------\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\nJkyIl1m4cCE2m41p06YBcMEFFwAwbdo0ysrK4vddf70R/v+GG27grrvu6jbetrY2PvvsMxYvXhw/\n12X9OfPMM/n617/ONddcEx/ryUq604kvvM//pTXgR4COUIhmvw+nzU5nKMTN008l1+1mxrC8A+a/\n6+LyZU/T6PPxtamGD86K4m2EohHy3G6+fephZbzQaE56Br2C0+zz0Rrwk+VykeVKjp//2j+fQym4\n+yvnsKGuFoBvzpjF//nQyw9O+RMAv9t9DQBLF88bUJu7W5rxh0Pkm1aiFcXbAJhXUMDulmZmDMs7\n7HFpBh8pCdv9d+/ezW9/+1vWrl1LRkYGN954YzypJkCS+QNmtVrjSsE999zDZZddxmuvvca8efN4\n9913AXop1T2P7XY769at45133uH555/nkUce4e233+a2227j7rvvZuHChaxcuZIHH3ywV/tdSTG7\nsFgs3ZJq7k+hV0qRk5MT90lK5C9/+Qtr1qzhf//3fzn11FPZsGEDmZmZ/dZ1vOMNBtnT0kxExRib\nkUV28j5ZYxUhPzWVTKeTYDSK3WIhxeHg85rq+PW0pCSumXJwVpsurl+xnB3NTQD8c8f2+Hm71cq2\nhgYCkXCvkBYajebgGbQKTjga5cUd2/m8pgqLWIjFFKcV5HPFxEK+/tIL8S2cv/joA4a53XFzsgA3\nrLoMgLmH6P8bikZRfTgIKoyggpqjQ5el5khbbvqivb2d1NRU0tLSqK2t5a233uLiiy/eb5m9e/dS\nVFREUVERa9asYefOnTidTj777DMqKirIz8/nueee65WY0+v1EggEuPTSSznjjDOYOHEiAB6Ph/z8\nfCPW01NPHdI4li9fzh133MHSpUs588wzu13LzMwkLy+PF198kSuvvJJYLMaWLVuYPn06JSUlzJs3\nj7lz5/Laa69RXV19wio4O5oa+fumDYSjMRQKiwiXTpjI2aPGxO8REV65/qZu5fraqHAg+ivT6OsE\n9mUWX1Veig5grNEcHoNWwVldXsaa6iryU9OwiBBTik8rK8lOsOIABCNRRIzQ5hYRli5eckiCJ5Ff\nfPQBlR4PDqsVEaHa2270qayMH8876/AGpjkuOPXUUyksLGTSpEmMGjWql3LQF7/85S/58MMPsVgs\nFBUVceGFF7J69WpOO+00vvvd77J3717mz5/PZZdd1q2cx+PhqquuIhgMEovFePjhhwFjl9eVV15J\n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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# display transported samples\n", + "pl.figure(4, figsize=(8, 4))\n", + "pl.subplot(1, 2, 1)\n", + "pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o',\n", + " label='Target samples', alpha=0.5)\n", + "pl.scatter(transp_Xs_sinkhorn_un[:, 0], transp_Xs_sinkhorn_un[:, 1], c=ys,\n", + " marker='+', label='Transp samples', s=30)\n", + "pl.title('Transported samples\\nEmdTransport')\n", + "pl.legend(loc=0)\n", + "pl.xticks([])\n", + "pl.yticks([])\n", + "\n", + "pl.subplot(1, 2, 2)\n", + "pl.scatter(Xt[:, 0], Xt[:, 1], c=yt, marker='o',\n", + " label='Target samples', alpha=0.5)\n", + "pl.scatter(transp_Xs_sinkhorn_semi[:, 0], transp_Xs_sinkhorn_semi[:, 1], c=ys,\n", + " marker='+', label='Transp samples', s=30)\n", + "pl.title('Transported samples\\nSinkhornTransport')\n", + "pl.xticks([])\n", + "pl.yticks([])\n", + "\n", + "pl.tight_layout()\n", + "pl.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} -- cgit v1.2.3