summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRémi Flamary <remi.flamary@gmail.com>2017-07-24 11:15:33 +0200
committerRémi Flamary <remi.flamary@gmail.com>2017-07-24 11:15:33 +0200
commit5a6b5de9b2f28c93bef1a9db2e3b94693c05ff4f (patch)
tree1f7457a028ef71253be36c44fb87c2e4131e909a
parent82da63f1020835a412f6174500099694a78ab6be (diff)
add proper testing
-rw-r--r--.travis.yml2
-rw-r--r--Makefile13
-rw-r--r--docs/source/readme.rst52
-rw-r--r--test/test_emd_multi.py47
-rw-r--r--test/test_gpu.py59
-rw-r--r--test/test_gpu_sinkhorn.py28
-rw-r--r--test/test_gpu_sinkhorn_lpl1.py29
-rw-r--r--test/test_load_module.py10
-rw-r--r--test/test_ot.py55
9 files changed, 164 insertions, 131 deletions
diff --git a/.travis.yml b/.travis.yml
index 8a95d7c..1c3a18c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -20,6 +20,6 @@ install:
- python setup.py install
# command to run tests + check syntax style
script:
- - python test/test_load_module.py -v
- flake8 examples/ ot/ test/
+ - python -m py.test -v
# - py.test ot test
diff --git a/Makefile b/Makefile
index c6a83c8..ff03a63 100644
--- a/Makefile
+++ b/Makefile
@@ -31,22 +31,25 @@ sremove :
tr '\n' '\0' < files.txt | sudo xargs -0 rm -f --
rm files.txt
-clean :
+clean : FORCE
$(PYTHON) setup.py clean
pep8 :
flake8 examples/ ot/ test/
-test:
- pytest
+test : FORCE pep8
+ python -m py.test -v
-uploadpypi:
+uploadpypi :
#python setup.py register
python setup.py sdist upload -r pypi
-rdoc:
+rdoc :
pandoc --from=markdown --to=rst --output=docs/source/readme.rst README.md
notebook :
ipython notebook --matplotlib=inline --notebook-dir=notebooks/
+
+
+FORCE :
diff --git a/docs/source/readme.rst b/docs/source/readme.rst
index 611001b..c1e0017 100644
--- a/docs/source/readme.rst
+++ b/docs/source/readme.rst
@@ -28,8 +28,8 @@ available in the examples folder.
Installation
------------
-The Library has been tested on Linux and MacOSX. It requires a C++
-compiler for using the EMD solver and rely on the following Python
+The library has been tested on Linux, MacOSX and Windows. It requires a
+C++ compiler for using the EMD solver and relies on the following Python
modules:
- Numpy (>=1.11)
@@ -37,25 +37,34 @@ modules:
- Cython (>=0.23)
- Matplotlib (>=1.5)
-Under debian based linux the dependencies can be installed with
+Pip installation
+^^^^^^^^^^^^^^^^
+
+You can install the toolbox through PyPI with:
::
- sudo apt-get install python-numpy python-scipy python-matplotlib cython
+ pip install POT
-To install the library, you can install it locally (after downloading
-it) on you machine using
+or get the very latest version by downloading it and then running:
::
python setup.py install --user # for user install (no root)
-The toolbox is also available on PyPI with a possibly slightly older
-version. You can install it with:
+Anaconda installation with conda-forge
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you use the Anaconda python distribution, POT is available in
+`conda-forge <https://conda-forge.org>`__. To install it and the
+required dependencies:
::
- pip install POT
+ conda install -c conda-forge pot
+
+Post installation check
+^^^^^^^^^^^^^^^^^^^^^^^
After a correct installation, you should be able to import the module
without errors:
@@ -109,6 +118,7 @@ Short examples
# a,b are 1D histograms (sum to 1 and positive)
# M is the ground cost matrix
Wd=ot.emd2(a,b,M) # exact linear program
+ Wd_reg=ot.sinkhorn2(a,b,M,reg) # entropic regularized OT
# if b is a matrix compute all distances to a and return a vector
- Compute OT matrix
@@ -117,8 +127,8 @@ Short examples
# a,b are 1D histograms (sum to 1 and positive)
# M is the ground cost matrix
- Totp=ot.emd(a,b,M) # exact linear program
- Totp_reg=ot.sinkhorn(a,b,M,reg) # entropic regularized OT
+ T=ot.emd(a,b,M) # exact linear program
+ T_reg=ot.sinkhorn(a,b,M,reg) # entropic regularized OT
- Compute Wasserstein barycenter
@@ -172,6 +182,7 @@ The contributors to this library are:
- `Rémi Flamary <http://remi.flamary.com/>`__
- `Nicolas Courty <http://people.irisa.fr/Nicolas.Courty/>`__
+- `Alexandre Gramfort <http://alexandre.gramfort.net/>`__
- `Laetitia Chapel <http://people.irisa.fr/Laetitia.Chapel/>`__
- `Michael Perrot <http://perso.univ-st-etienne.fr/pem82055/>`__
(Mapping estimation)
@@ -189,6 +200,25 @@ languages):
- `Marco Cuturi <http://marcocuturi.net/>`__ (Sinkhorn Knopp in
Matlab/Cuda)
+Contributions and code of conduct
+---------------------------------
+
+Every contribution is welcome and should respect the `contribution
+guidelines <CONTRIBUTING.md>`__. Each member of the project is expected
+to follow the `code of conduct <CODE_OF_CONDUCT.md>`__.
+
+Support
+-------
+
+You can ask questions and join the development discussion:
+
+- On the `POT Slack channel <https://pot-toolbox.slack.com>`__
+- On the POT `mailing
+ list <https://mail.python.org/mm3/mailman3/lists/pot.python.org/>`__
+
+You can also post bug reports and feature requests in Github issues.
+Make sure to read our `guidelines <CONTRIBUTING.md>`__ first.
+
References
----------
diff --git a/test/test_emd_multi.py b/test/test_emd_multi.py
deleted file mode 100644
index 2eef242..0000000
--- a/test/test_emd_multi.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python2
-# -*- coding: utf-8 -*-
-"""
-Created on Fri Mar 10 09:56:06 2017
-
-@author: rflamary
-"""
-
-import numpy as np
-
-import ot
-from ot.datasets import get_1D_gauss as gauss
-# reload(ot.lp)
-
-#%% parameters
-
-n = 5000 # nb bins
-
-# bin positions
-x = np.arange(n, dtype=np.float64)
-
-# Gaussian distributions
-a = gauss(n, m=20, s=5) # m= mean, s= std
-
-ls = np.arange(20, 1000, 10)
-nb = len(ls)
-b = np.zeros((n, nb))
-for i in range(nb):
- b[:, i] = gauss(n, m=ls[i], s=10)
-
-# loss matrix
-M = ot.dist(x.reshape((n, 1)), x.reshape((n, 1)))
-# M/=M.max()
-
-#%%
-
-print('Computing {} EMD '.format(nb))
-
-# emd loss 1 proc
-ot.tic()
-emd_loss4 = ot.emd2(a, b, M, 1)
-ot.toc('1 proc : {} s')
-
-# emd loss multipro proc
-ot.tic()
-emd_loss4 = ot.emd2(a, b, M)
-ot.toc('multi proc : {} s')
diff --git a/test/test_gpu.py b/test/test_gpu.py
new file mode 100644
index 0000000..312a2d4
--- /dev/null
+++ b/test/test_gpu.py
@@ -0,0 +1,59 @@
+import ot
+import numpy as np
+import time
+import pytest
+
+
+@pytest.mark.skip(reason="No way to test GPU on travis yet")
+def test_gpu_sinkhorn():
+ import ot.gpu
+
+ def describeRes(r):
+ print("min:{:.3E}, max::{:.3E}, mean::{:.3E}, std::{:.3E}".format(
+ np.min(r), np.max(r), np.mean(r), np.std(r)))
+
+ for n in [5000]:
+ print(n)
+ a = np.random.rand(n // 4, 100)
+ b = np.random.rand(n, 100)
+ time1 = time.time()
+ transport = ot.da.OTDA_sinkhorn()
+ transport.fit(a, b)
+ G1 = transport.G
+ time2 = time.time()
+ transport = ot.gpu.da.OTDA_sinkhorn()
+ transport.fit(a, b)
+ G2 = transport.G
+ time3 = time.time()
+ print("Normal sinkhorn, time: {:6.2f} sec ".format(time2 - time1))
+ describeRes(G1)
+ print(" GPU sinkhorn, time: {:6.2f} sec ".format(time3 - time2))
+ describeRes(G2)
+
+
+@pytest.mark.skip(reason="No way to test GPU on travis yet")
+def test_gpu_sinkhorn_lpl1():
+ def describeRes(r):
+ print("min:{:.3E}, max:{:.3E}, mean:{:.3E}, std:{:.3E}"
+ .format(np.min(r), np.max(r), np.mean(r), np.std(r)))
+
+ for n in [5000]:
+ print(n)
+ a = np.random.rand(n // 4, 100)
+ labels_a = np.random.randint(10, size=(n // 4))
+ b = np.random.rand(n, 100)
+ time1 = time.time()
+ transport = ot.da.OTDA_lpl1()
+ transport.fit(a, labels_a, b)
+ G1 = transport.G
+ time2 = time.time()
+ transport = ot.gpu.da.OTDA_lpl1()
+ transport.fit(a, labels_a, b)
+ G2 = transport.G
+ time3 = time.time()
+ print("Normal sinkhorn lpl1, time: {:6.2f} sec ".format(
+ time2 - time1))
+ describeRes(G1)
+ print(" GPU sinkhorn lpl1, time: {:6.2f} sec ".format(
+ time3 - time2))
+ describeRes(G2)
diff --git a/test/test_gpu_sinkhorn.py b/test/test_gpu_sinkhorn.py
deleted file mode 100644
index 841f062..0000000
--- a/test/test_gpu_sinkhorn.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import ot
-import numpy as np
-import time
-import ot.gpu
-
-
-def describeRes(r):
- print("min:{:.3E}, max::{:.3E}, mean::{:.3E}, std::{:.3E}".format(
- np.min(r), np.max(r), np.mean(r), np.std(r)))
-
-
-for n in [5000, 10000, 15000, 20000]:
- print(n)
- a = np.random.rand(n // 4, 100)
- b = np.random.rand(n, 100)
- time1 = time.time()
- transport = ot.da.OTDA_sinkhorn()
- transport.fit(a, b)
- G1 = transport.G
- time2 = time.time()
- transport = ot.gpu.da.OTDA_sinkhorn()
- transport.fit(a, b)
- G2 = transport.G
- time3 = time.time()
- print("Normal sinkhorn, time: {:6.2f} sec ".format(time2 - time1))
- describeRes(G1)
- print(" GPU sinkhorn, time: {:6.2f} sec ".format(time3 - time2))
- describeRes(G2)
diff --git a/test/test_gpu_sinkhorn_lpl1.py b/test/test_gpu_sinkhorn_lpl1.py
deleted file mode 100644
index f0eb7e6..0000000
--- a/test/test_gpu_sinkhorn_lpl1.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import ot
-import numpy as np
-import time
-import ot.gpu
-
-
-def describeRes(r):
- print("min:{:.3E}, max:{:.3E}, mean:{:.3E}, std:{:.3E}"
- .format(np.min(r), np.max(r), np.mean(r), np.std(r)))
-
-
-for n in [5000, 10000, 15000, 20000]:
- print(n)
- a = np.random.rand(n // 4, 100)
- labels_a = np.random.randint(10, size=(n // 4))
- b = np.random.rand(n, 100)
- time1 = time.time()
- transport = ot.da.OTDA_lpl1()
- transport.fit(a, labels_a, b)
- G1 = transport.G
- time2 = time.time()
- transport = ot.gpu.da.OTDA_lpl1()
- transport.fit(a, labels_a, b)
- G2 = transport.G
- time3 = time.time()
- print("Normal sinkhorn lpl1, time: {:6.2f} sec ".format(time2 - time1))
- describeRes(G1)
- print(" GPU sinkhorn lpl1, time: {:6.2f} sec ".format(time3 - time2))
- describeRes(G2)
diff --git a/test/test_load_module.py b/test/test_load_module.py
deleted file mode 100644
index d77261e..0000000
--- a/test/test_load_module.py
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-import ot
-import doctest
-
-# test lp solver
-doctest.testmod(ot.lp, verbose=True)
-
-# test bregman solver
-doctest.testmod(ot.bregman, verbose=True)
diff --git a/test/test_ot.py b/test/test_ot.py
new file mode 100644
index 0000000..51ee510
--- /dev/null
+++ b/test/test_ot.py
@@ -0,0 +1,55 @@
+
+
+import ot
+import numpy as np
+
+#import pytest
+
+
+def test_doctest():
+
+ import doctest
+
+ # test lp solver
+ doctest.testmod(ot.lp, verbose=True)
+
+ # test bregman solver
+ doctest.testmod(ot.bregman, verbose=True)
+
+
+#@pytest.mark.skip(reason="Seems to be a conflict between pytest and multiprocessing")
+def test_emd_multi():
+
+ from ot.datasets import get_1D_gauss as gauss
+
+ n = 1000 # nb bins
+
+ # bin positions
+ x = np.arange(n, dtype=np.float64)
+
+ # Gaussian distributions
+ a = gauss(n, m=20, s=5) # m= mean, s= std
+
+ ls = np.arange(20, 1000, 10)
+ nb = len(ls)
+ b = np.zeros((n, nb))
+ for i in range(nb):
+ b[:, i] = gauss(n, m=ls[i], s=10)
+
+ # loss matrix
+ M = ot.dist(x.reshape((n, 1)), x.reshape((n, 1)))
+ # M/=M.max()
+
+ print('Computing {} EMD '.format(nb))
+
+ # emd loss 1 proc
+ ot.tic()
+ emd1 = ot.emd2(a, b, M, 1)
+ ot.toc('1 proc : {} s')
+
+ # emd loss multipro proc
+ ot.tic()
+ emdn = ot.emd2(a, b, M)
+ ot.toc('multi proc : {} s')
+
+ assert np.allclose(emd1, emdn)