diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/test_bregman.py | 137 | ||||
-rw-r--r-- | test/test_da.py | 469 | ||||
-rw-r--r-- | test/test_dr.py | 59 | ||||
-rw-r--r-- | test/test_emd_multi.py | 48 | ||||
-rw-r--r-- | test/test_gpu.py | 79 | ||||
-rw-r--r-- | test/test_gpu_sinkhorn.py | 26 | ||||
-rw-r--r-- | test/test_gpu_sinkhorn_lpl1.py | 28 | ||||
-rw-r--r-- | test/test_load_module.py | 10 | ||||
-rw-r--r-- | test/test_optim.py | 67 | ||||
-rw-r--r-- | test/test_ot.py | 102 | ||||
-rw-r--r-- | test/test_plot.py | 49 | ||||
-rw-r--r-- | test/test_utils.py | 125 |
12 files changed, 1087 insertions, 112 deletions
diff --git a/test/test_bregman.py b/test/test_bregman.py new file mode 100644 index 0000000..4a800fd --- /dev/null +++ b/test/test_bregman.py @@ -0,0 +1,137 @@ +"""Tests for module bregman on OT with bregman projections """ + +# Author: Remi Flamary <remi.flamary@unice.fr> +# +# License: MIT License + +import numpy as np +import ot + + +def test_sinkhorn(): + # test sinkhorn + n = 100 + rng = np.random.RandomState(0) + + x = rng.randn(n, 2) + u = ot.utils.unif(n) + + M = ot.dist(x, x) + + G = ot.sinkhorn(u, u, M, 1, stopThr=1e-10) + + # check constratints + np.testing.assert_allclose( + u, G.sum(1), atol=1e-05) # cf convergence sinkhorn + np.testing.assert_allclose( + u, G.sum(0), atol=1e-05) # cf convergence sinkhorn + + +def test_sinkhorn_empty(): + # test sinkhorn + n = 100 + rng = np.random.RandomState(0) + + x = rng.randn(n, 2) + u = ot.utils.unif(n) + + M = ot.dist(x, x) + + G, log = ot.sinkhorn([], [], M, 1, stopThr=1e-10, verbose=True, log=True) + # check constratints + np.testing.assert_allclose(u, G.sum(1), atol=1e-05) + np.testing.assert_allclose(u, G.sum(0), atol=1e-05) + + G, log = ot.sinkhorn([], [], M, 1, stopThr=1e-10, + method='sinkhorn_stabilized', verbose=True, log=True) + # check constratints + np.testing.assert_allclose(u, G.sum(1), atol=1e-05) + np.testing.assert_allclose(u, G.sum(0), atol=1e-05) + + G, log = ot.sinkhorn( + [], [], M, 1, stopThr=1e-10, method='sinkhorn_epsilon_scaling', + verbose=True, log=True) + # check constratints + np.testing.assert_allclose(u, G.sum(1), atol=1e-05) + np.testing.assert_allclose(u, G.sum(0), atol=1e-05) + + +def test_sinkhorn_variants(): + # test sinkhorn + n = 100 + rng = np.random.RandomState(0) + + x = rng.randn(n, 2) + u = ot.utils.unif(n) + + M = ot.dist(x, x) + + G0 = ot.sinkhorn(u, u, M, 1, method='sinkhorn', stopThr=1e-10) + Gs = ot.sinkhorn(u, u, M, 1, method='sinkhorn_stabilized', stopThr=1e-10) + Ges = ot.sinkhorn( + u, u, M, 1, method='sinkhorn_epsilon_scaling', stopThr=1e-10) + Gerr = ot.sinkhorn(u, u, M, 1, method='do_not_exists', stopThr=1e-10) + + # check values + np.testing.assert_allclose(G0, Gs, atol=1e-05) + np.testing.assert_allclose(G0, Ges, atol=1e-05) + np.testing.assert_allclose(G0, Gerr) + + +def test_bary(): + + n_bins = 100 # nb bins + + # Gaussian distributions + a1 = ot.datasets.get_1D_gauss(n_bins, m=30, s=10) # m= mean, s= std + a2 = ot.datasets.get_1D_gauss(n_bins, m=40, s=10) + + # creating matrix A containing all distributions + A = np.vstack((a1, a2)).T + + # loss matrix + normalization + M = ot.utils.dist0(n_bins) + M /= M.max() + + alpha = 0.5 # 0<=alpha<=1 + weights = np.array([1 - alpha, alpha]) + + # wasserstein + reg = 1e-3 + bary_wass = ot.bregman.barycenter(A, M, reg, weights) + + np.testing.assert_allclose(1, np.sum(bary_wass)) + + ot.bregman.barycenter(A, M, reg, log=True, verbose=True) + + +def test_unmix(): + + n_bins = 50 # nb bins + + # Gaussian distributions + a1 = ot.datasets.get_1D_gauss(n_bins, m=20, s=10) # m= mean, s= std + a2 = ot.datasets.get_1D_gauss(n_bins, m=40, s=10) + + a = ot.datasets.get_1D_gauss(n_bins, m=30, s=10) + + # creating matrix A containing all distributions + D = np.vstack((a1, a2)).T + + # loss matrix + normalization + M = ot.utils.dist0(n_bins) + M /= M.max() + + M0 = ot.utils.dist0(2) + M0 /= M0.max() + h0 = ot.unif(2) + + # wasserstein + reg = 1e-3 + um = ot.bregman.unmix(a, D, M, M0, h0, reg, 1, alpha=0.01,) + + np.testing.assert_allclose(1, np.sum(um), rtol=1e-03, atol=1e-03) + np.testing.assert_allclose([0.5, 0.5], um, rtol=1e-03, atol=1e-03) + + ot.bregman.unmix(a, D, M, M0, h0, reg, + 1, alpha=0.01, log=True, verbose=True) diff --git a/test/test_da.py b/test/test_da.py new file mode 100644 index 0000000..104a798 --- /dev/null +++ b/test/test_da.py @@ -0,0 +1,469 @@ +"""Tests for module da on Domain Adaptation """ + +# Author: Remi Flamary <remi.flamary@unice.fr> +# +# License: MIT License + +import numpy as np +from numpy.testing.utils import assert_allclose, assert_equal + +import ot +from ot.datasets import get_data_classif +from ot.utils import unif + + +def test_sinkhorn_lpl1_transport_class(): + """test_sinkhorn_transport + """ + + ns = 150 + nt = 200 + + Xs, ys = get_data_classif('3gauss', ns) + Xt, yt = get_data_classif('3gauss2', nt) + + clf = ot.da.SinkhornLpl1Transport() + + # test its computed + clf.fit(Xs=Xs, ys=ys, Xt=Xt) + assert hasattr(clf, "cost_") + assert hasattr(clf, "coupling_") + + # test dimensions of coupling + assert_equal(clf.cost_.shape, ((Xs.shape[0], Xt.shape[0]))) + assert_equal(clf.coupling_.shape, ((Xs.shape[0], Xt.shape[0]))) + + # test margin constraints + mu_s = unif(ns) + mu_t = unif(nt) + assert_allclose(np.sum(clf.coupling_, axis=0), mu_t, rtol=1e-3, atol=1e-3) + assert_allclose(np.sum(clf.coupling_, axis=1), mu_s, rtol=1e-3, atol=1e-3) + + # test transform + transp_Xs = clf.transform(Xs=Xs) + assert_equal(transp_Xs.shape, Xs.shape) + + Xs_new, _ = get_data_classif('3gauss', ns + 1) + transp_Xs_new = clf.transform(Xs_new) + + # check that the oos method is working + assert_equal(transp_Xs_new.shape, Xs_new.shape) + + # test inverse transform + transp_Xt = clf.inverse_transform(Xt=Xt) + assert_equal(transp_Xt.shape, Xt.shape) + + Xt_new, _ = get_data_classif('3gauss2', nt + 1) + transp_Xt_new = clf.inverse_transform(Xt=Xt_new) + + # check that the oos method is working + assert_equal(transp_Xt_new.shape, Xt_new.shape) + + # test fit_transform + transp_Xs = clf.fit_transform(Xs=Xs, ys=ys, Xt=Xt) + assert_equal(transp_Xs.shape, Xs.shape) + + # test semi supervised mode + clf = ot.da.SinkhornLpl1Transport() + clf.fit(Xs=Xs, ys=ys, Xt=Xt) + n_unsup = np.sum(clf.cost_) + + # test semi supervised mode + clf = ot.da.SinkhornLpl1Transport() + clf.fit(Xs=Xs, ys=ys, Xt=Xt, yt=yt) + assert_equal(clf.cost_.shape, ((Xs.shape[0], Xt.shape[0]))) + n_semisup = np.sum(clf.cost_) + + assert n_unsup != n_semisup, "semisupervised mode not working" + + +def test_sinkhorn_l1l2_transport_class(): + """test_sinkhorn_transport + """ + + ns = 150 + nt = 200 + + Xs, ys = get_data_classif('3gauss', ns) + Xt, yt = get_data_classif('3gauss2', nt) + + clf = ot.da.SinkhornL1l2Transport() + + # test its computed + clf.fit(Xs=Xs, ys=ys, Xt=Xt) + assert hasattr(clf, "cost_") + assert hasattr(clf, "coupling_") + assert hasattr(clf, "log_") + + # test dimensions of coupling + assert_equal(clf.cost_.shape, ((Xs.shape[0], Xt.shape[0]))) + assert_equal(clf.coupling_.shape, ((Xs.shape[0], Xt.shape[0]))) + + # test margin constraints + mu_s = unif(ns) + mu_t = unif(nt) + assert_allclose(np.sum(clf.coupling_, axis=0), mu_t, rtol=1e-3, atol=1e-3) + assert_allclose(np.sum(clf.coupling_, axis=1), mu_s, rtol=1e-3, atol=1e-3) + + # test transform + transp_Xs = clf.transform(Xs=Xs) + assert_equal(transp_Xs.shape, Xs.shape) + + Xs_new, _ = get_data_classif('3gauss', ns + 1) + transp_Xs_new = clf.transform(Xs_new) + + # check that the oos method is working + assert_equal(transp_Xs_new.shape, Xs_new.shape) + + # test inverse transform + transp_Xt = clf.inverse_transform(Xt=Xt) + assert_equal(transp_Xt.shape, Xt.shape) + + Xt_new, _ = get_data_classif('3gauss2', nt + 1) + transp_Xt_new = clf.inverse_transform(Xt=Xt_new) + + # check that the oos method is working + assert_equal(transp_Xt_new.shape, Xt_new.shape) + + # test fit_transform + transp_Xs = clf.fit_transform(Xs=Xs, ys=ys, Xt=Xt) + assert_equal(transp_Xs.shape, Xs.shape) + + # test semi supervised mode + clf = ot.da.SinkhornL1l2Transport() + clf.fit(Xs=Xs, ys=ys, Xt=Xt) + n_unsup = np.sum(clf.cost_) + + # test semi supervised mode + clf = ot.da.SinkhornL1l2Transport() + clf.fit(Xs=Xs, ys=ys, Xt=Xt, yt=yt) + assert_equal(clf.cost_.shape, ((Xs.shape[0], Xt.shape[0]))) + n_semisup = np.sum(clf.cost_) + + assert n_unsup != n_semisup, "semisupervised mode not working" + + # check everything runs well with log=True + clf = ot.da.SinkhornL1l2Transport(log=True) + clf.fit(Xs=Xs, ys=ys, Xt=Xt) + assert len(clf.log_.keys()) != 0 + + +def test_sinkhorn_transport_class(): + """test_sinkhorn_transport + """ + + ns = 150 + nt = 200 + + Xs, ys = get_data_classif('3gauss', ns) + Xt, yt = get_data_classif('3gauss2', nt) + + clf = ot.da.SinkhornTransport() + + # test its computed + clf.fit(Xs=Xs, Xt=Xt) + assert hasattr(clf, "cost_") + assert hasattr(clf, "coupling_") + assert hasattr(clf, "log_") + + # test dimensions of coupling + assert_equal(clf.cost_.shape, ((Xs.shape[0], Xt.shape[0]))) + assert_equal(clf.coupling_.shape, ((Xs.shape[0], Xt.shape[0]))) + + # test margin constraints + mu_s = unif(ns) + mu_t = unif(nt) + assert_allclose(np.sum(clf.coupling_, axis=0), mu_t, rtol=1e-3, atol=1e-3) + assert_allclose(np.sum(clf.coupling_, axis=1), mu_s, rtol=1e-3, atol=1e-3) + + # test transform + transp_Xs = clf.transform(Xs=Xs) + assert_equal(transp_Xs.shape, Xs.shape) + + Xs_new, _ = get_data_classif('3gauss', ns + 1) + transp_Xs_new = clf.transform(Xs_new) + + # check that the oos method is working + assert_equal(transp_Xs_new.shape, Xs_new.shape) + + # test inverse transform + transp_Xt = clf.inverse_transform(Xt=Xt) + assert_equal(transp_Xt.shape, Xt.shape) + + Xt_new, _ = get_data_classif('3gauss2', nt + 1) + transp_Xt_new = clf.inverse_transform(Xt=Xt_new) + + # check that the oos method is working + assert_equal(transp_Xt_new.shape, Xt_new.shape) + + # test fit_transform + transp_Xs = clf.fit_transform(Xs=Xs, Xt=Xt) + assert_equal(transp_Xs.shape, Xs.shape) + + # test semi supervised mode + clf = ot.da.SinkhornTransport() + clf.fit(Xs=Xs, Xt=Xt) + n_unsup = np.sum(clf.cost_) + + # test semi supervised mode + clf = ot.da.SinkhornTransport() + clf.fit(Xs=Xs, ys=ys, Xt=Xt, yt=yt) + assert_equal(clf.cost_.shape, ((Xs.shape[0], Xt.shape[0]))) + n_semisup = np.sum(clf.cost_) + + assert n_unsup != n_semisup, "semisupervised mode not working" + + # check everything runs well with log=True + clf = ot.da.SinkhornTransport(log=True) + clf.fit(Xs=Xs, ys=ys, Xt=Xt) + assert len(clf.log_.keys()) != 0 + + +def test_emd_transport_class(): + """test_sinkhorn_transport + """ + + ns = 150 + nt = 200 + + Xs, ys = get_data_classif('3gauss', ns) + Xt, yt = get_data_classif('3gauss2', nt) + + clf = ot.da.EMDTransport() + + # test its computed + clf.fit(Xs=Xs, Xt=Xt) + assert hasattr(clf, "cost_") + assert hasattr(clf, "coupling_") + + # test dimensions of coupling + assert_equal(clf.cost_.shape, ((Xs.shape[0], Xt.shape[0]))) + assert_equal(clf.coupling_.shape, ((Xs.shape[0], Xt.shape[0]))) + + # test margin constraints + mu_s = unif(ns) + mu_t = unif(nt) + assert_allclose(np.sum(clf.coupling_, axis=0), mu_t, rtol=1e-3, atol=1e-3) + assert_allclose(np.sum(clf.coupling_, axis=1), mu_s, rtol=1e-3, atol=1e-3) + + # test transform + transp_Xs = clf.transform(Xs=Xs) + assert_equal(transp_Xs.shape, Xs.shape) + + Xs_new, _ = get_data_classif('3gauss', ns + 1) + transp_Xs_new = clf.transform(Xs_new) + + # check that the oos method is working + assert_equal(transp_Xs_new.shape, Xs_new.shape) + + # test inverse transform + transp_Xt = clf.inverse_transform(Xt=Xt) + assert_equal(transp_Xt.shape, Xt.shape) + + Xt_new, _ = get_data_classif('3gauss2', nt + 1) + transp_Xt_new = clf.inverse_transform(Xt=Xt_new) + + # check that the oos method is working + assert_equal(transp_Xt_new.shape, Xt_new.shape) + + # test fit_transform + transp_Xs = clf.fit_transform(Xs=Xs, Xt=Xt) + assert_equal(transp_Xs.shape, Xs.shape) + + # test semi supervised mode + clf = ot.da.EMDTransport() + clf.fit(Xs=Xs, Xt=Xt) + n_unsup = np.sum(clf.cost_) + + # test semi supervised mode + clf = ot.da.EMDTransport() + clf.fit(Xs=Xs, ys=ys, Xt=Xt, yt=yt) + assert_equal(clf.cost_.shape, ((Xs.shape[0], Xt.shape[0]))) + n_semisup = np.sum(clf.cost_) + + assert n_unsup != n_semisup, "semisupervised mode not working" + + +def test_mapping_transport_class(): + """test_mapping_transport + """ + + ns = 150 + nt = 200 + + Xs, ys = get_data_classif('3gauss', ns) + Xt, yt = get_data_classif('3gauss2', nt) + Xs_new, _ = get_data_classif('3gauss', ns + 1) + + ########################################################################## + # kernel == linear mapping tests + ########################################################################## + + # check computation and dimensions if bias == False + clf = ot.da.MappingTransport(kernel="linear", bias=False) + clf.fit(Xs=Xs, Xt=Xt) + assert hasattr(clf, "coupling_") + assert hasattr(clf, "mapping_") + assert hasattr(clf, "log_") + + assert_equal(clf.coupling_.shape, ((Xs.shape[0], Xt.shape[0]))) + assert_equal(clf.mapping_.shape, ((Xs.shape[1], Xt.shape[1]))) + + # test margin constraints + mu_s = unif(ns) + mu_t = unif(nt) + assert_allclose(np.sum(clf.coupling_, axis=0), mu_t, rtol=1e-3, atol=1e-3) + assert_allclose(np.sum(clf.coupling_, axis=1), mu_s, rtol=1e-3, atol=1e-3) + + # test transform + transp_Xs = clf.transform(Xs=Xs) + assert_equal(transp_Xs.shape, Xs.shape) + + transp_Xs_new = clf.transform(Xs_new) + + # check that the oos method is working + assert_equal(transp_Xs_new.shape, Xs_new.shape) + + # check computation and dimensions if bias == True + clf = ot.da.MappingTransport(kernel="linear", bias=True) + clf.fit(Xs=Xs, Xt=Xt) + assert_equal(clf.coupling_.shape, ((Xs.shape[0], Xt.shape[0]))) + assert_equal(clf.mapping_.shape, ((Xs.shape[1] + 1, Xt.shape[1]))) + + # test margin constraints + mu_s = unif(ns) + mu_t = unif(nt) + assert_allclose(np.sum(clf.coupling_, axis=0), mu_t, rtol=1e-3, atol=1e-3) + assert_allclose(np.sum(clf.coupling_, axis=1), mu_s, rtol=1e-3, atol=1e-3) + + # test transform + transp_Xs = clf.transform(Xs=Xs) + assert_equal(transp_Xs.shape, Xs.shape) + + transp_Xs_new = clf.transform(Xs_new) + + # check that the oos method is working + assert_equal(transp_Xs_new.shape, Xs_new.shape) + + ########################################################################## + # kernel == gaussian mapping tests + ########################################################################## + + # check computation and dimensions if bias == False + clf = ot.da.MappingTransport(kernel="gaussian", bias=False) + clf.fit(Xs=Xs, Xt=Xt) + + assert_equal(clf.coupling_.shape, ((Xs.shape[0], Xt.shape[0]))) + assert_equal(clf.mapping_.shape, ((Xs.shape[0], Xt.shape[1]))) + + # test margin constraints + mu_s = unif(ns) + mu_t = unif(nt) + assert_allclose(np.sum(clf.coupling_, axis=0), mu_t, rtol=1e-3, atol=1e-3) + assert_allclose(np.sum(clf.coupling_, axis=1), mu_s, rtol=1e-3, atol=1e-3) + + # test transform + transp_Xs = clf.transform(Xs=Xs) + assert_equal(transp_Xs.shape, Xs.shape) + + transp_Xs_new = clf.transform(Xs_new) + + # check that the oos method is working + assert_equal(transp_Xs_new.shape, Xs_new.shape) + + # check computation and dimensions if bias == True + clf = ot.da.MappingTransport(kernel="gaussian", bias=True) + clf.fit(Xs=Xs, Xt=Xt) + assert_equal(clf.coupling_.shape, ((Xs.shape[0], Xt.shape[0]))) + assert_equal(clf.mapping_.shape, ((Xs.shape[0] + 1, Xt.shape[1]))) + + # test margin constraints + mu_s = unif(ns) + mu_t = unif(nt) + assert_allclose(np.sum(clf.coupling_, axis=0), mu_t, rtol=1e-3, atol=1e-3) + assert_allclose(np.sum(clf.coupling_, axis=1), mu_s, rtol=1e-3, atol=1e-3) + + # test transform + transp_Xs = clf.transform(Xs=Xs) + assert_equal(transp_Xs.shape, Xs.shape) + + transp_Xs_new = clf.transform(Xs_new) + + # check that the oos method is working + assert_equal(transp_Xs_new.shape, Xs_new.shape) + + # check everything runs well with log=True + clf = ot.da.MappingTransport(kernel="gaussian", log=True) + clf.fit(Xs=Xs, Xt=Xt) + assert len(clf.log_.keys()) != 0 + + +def test_otda(): + + n_samples = 150 # nb samples + np.random.seed(0) + + xs, ys = ot.datasets.get_data_classif('3gauss', n_samples) + xt, yt = ot.datasets.get_data_classif('3gauss2', n_samples) + + a, b = ot.unif(n_samples), ot.unif(n_samples) + + # LP problem + da_emd = ot.da.OTDA() # init class + da_emd.fit(xs, xt) # fit distributions + da_emd.interp() # interpolation of source samples + da_emd.predict(xs) # interpolation of source samples + + np.testing.assert_allclose(a, np.sum(da_emd.G, 1)) + np.testing.assert_allclose(b, np.sum(da_emd.G, 0)) + + # sinkhorn regularization + lambd = 1e-1 + da_entrop = ot.da.OTDA_sinkhorn() + da_entrop.fit(xs, xt, reg=lambd) + da_entrop.interp() + da_entrop.predict(xs) + + np.testing.assert_allclose(a, np.sum(da_entrop.G, 1), rtol=1e-3, atol=1e-3) + np.testing.assert_allclose(b, np.sum(da_entrop.G, 0), rtol=1e-3, atol=1e-3) + + # 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) + da_lpl1.interp() + da_lpl1.predict(xs) + + np.testing.assert_allclose(a, np.sum(da_lpl1.G, 1), rtol=1e-3, atol=1e-3) + np.testing.assert_allclose(b, np.sum(da_lpl1.G, 0), rtol=1e-3, atol=1e-3) + + # 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) + da_l1l2.interp() + da_l1l2.predict(xs) + + np.testing.assert_allclose(a, np.sum(da_l1l2.G, 1), rtol=1e-3, atol=1e-3) + np.testing.assert_allclose(b, np.sum(da_l1l2.G, 0), rtol=1e-3, atol=1e-3) + + # linear mapping + da_emd = ot.da.OTDA_mapping_linear() # init class + da_emd.fit(xs, xt, numItermax=10) # fit distributions + da_emd.predict(xs) # interpolation of source samples + + # nonlinear mapping + da_emd = ot.da.OTDA_mapping_kernel() # init class + da_emd.fit(xs, xt, numItermax=10) # fit distributions + da_emd.predict(xs) # interpolation of source samples + + +# if __name__ == "__main__": + +# test_sinkhorn_transport_class() +# test_emd_transport_class() +# test_sinkhorn_l1l2_transport_class() +# test_sinkhorn_lpl1_transport_class() +# test_mapping_transport_class() diff --git a/test/test_dr.py b/test/test_dr.py new file mode 100644 index 0000000..915012d --- /dev/null +++ b/test/test_dr.py @@ -0,0 +1,59 @@ +"""Tests for module dr on Dimensionality Reduction """ + +# Author: Remi Flamary <remi.flamary@unice.fr> +# +# License: MIT License + +import numpy as np +import ot +import pytest + +try: # test if autograd and pymanopt are installed + import ot.dr + nogo = False +except ImportError: + nogo = True + + +@pytest.mark.skipif(nogo, reason="Missing modules (autograd or pymanopt)") +def test_fda(): + + n_samples = 90 # nb samples in source and target datasets + np.random.seed(0) + + # generate gaussian dataset + xs, ys = ot.datasets.get_data_classif('gaussrot', n_samples) + + n_features_noise = 8 + + xs = np.hstack((xs, np.random.randn(n_samples, n_features_noise))) + + p = 1 + + Pfda, projfda = ot.dr.fda(xs, ys, p) + + projfda(xs) + + np.testing.assert_allclose(np.sum(Pfda**2, 0), np.ones(p)) + + +@pytest.mark.skipif(nogo, reason="Missing modules (autograd or pymanopt)") +def test_wda(): + + n_samples = 100 # nb samples in source and target datasets + np.random.seed(0) + + # generate gaussian dataset + xs, ys = ot.datasets.get_data_classif('gaussrot', n_samples) + + n_features_noise = 8 + + xs = np.hstack((xs, np.random.randn(n_samples, n_features_noise))) + + p = 2 + + Pwda, projwda = ot.dr.wda(xs, ys, p, maxiter=10) + + projwda(xs) + + np.testing.assert_allclose(np.sum(Pwda**2, 0), np.ones(p)) diff --git a/test/test_emd_multi.py b/test/test_emd_multi.py deleted file mode 100644 index ee0a20e..0000000 --- a/test/test_emd_multi.py +++ /dev/null @@ -1,48 +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 pylab as pl -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= range(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..615c2a7 --- /dev/null +++ b/test/test_gpu.py @@ -0,0 +1,79 @@ +"""Tests for module gpu for gpu acceleration """ + +# Author: Remi Flamary <remi.flamary@unice.fr> +# +# License: MIT License + +import numpy as np +import ot +import time +import pytest + +try: # test if cudamat installed + import ot.gpu + nogpu = False +except ImportError: + nogpu = True + + +@pytest.mark.skipif(nogpu, reason="No GPU available") +def test_gpu_sinkhorn(): + + rng = np.random.RandomState(0) + + def describe_res(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_samples in [50, 100, 500, 1000]: + print(n_samples) + a = rng.rand(n_samples // 4, 100) + b = rng.rand(n_samples, 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)) + describe_res(G1) + print(" GPU sinkhorn, time: {:6.2f} sec ".format(time3 - time2)) + describe_res(G2) + + np.testing.assert_allclose(G1, G2, rtol=1e-5, atol=1e-5) + + +@pytest.mark.skipif(nogpu, reason="No GPU available") +def test_gpu_sinkhorn_lpl1(): + + rng = np.random.RandomState(0) + + def describe_res(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_samples in [50, 100, 500]: + print(n_samples) + a = rng.rand(n_samples // 4, 100) + labels_a = np.random.randint(10, size=(n_samples // 4)) + b = rng.rand(n_samples, 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)) + describe_res(G1) + print(" GPU sinkhorn lpl1, time: {:6.2f} sec ".format( + time3 - time2)) + describe_res(G2) + + np.testing.assert_allclose(G1, G2, rtol=1e-5, atol=1e-5) diff --git a/test/test_gpu_sinkhorn.py b/test/test_gpu_sinkhorn.py deleted file mode 100644 index bfa2cd2..0000000 --- a/test/test_gpu_sinkhorn.py +++ /dev/null @@ -1,26 +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)
\ No newline at end of file diff --git a/test/test_gpu_sinkhorn_lpl1.py b/test/test_gpu_sinkhorn_lpl1.py deleted file mode 100644 index e6cdd31..0000000 --- a/test/test_gpu_sinkhorn_lpl1.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) - 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 a04c5df..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_optim.py b/test/test_optim.py new file mode 100644 index 0000000..69496a5 --- /dev/null +++ b/test/test_optim.py @@ -0,0 +1,67 @@ +"""Tests for module optim fro OT optimization """ + +# Author: Remi Flamary <remi.flamary@unice.fr> +# +# License: MIT License + +import numpy as np +import ot + + +def test_conditional_gradient(): + + n_bins = 100 # nb bins + np.random.seed(0) + # bin positions + x = np.arange(n_bins, dtype=np.float64) + + # Gaussian distributions + a = ot.datasets.get_1D_gauss(n_bins, m=20, s=5) # m= mean, s= std + b = ot.datasets.get_1D_gauss(n_bins, m=60, s=10) + + # loss matrix + M = ot.dist(x.reshape((n_bins, 1)), x.reshape((n_bins, 1))) + M /= M.max() + + def f(G): + return 0.5 * np.sum(G**2) + + def df(G): + return G + + reg = 1e-1 + + G, log = ot.optim.cg(a, b, M, reg, f, df, verbose=True, log=True) + + np.testing.assert_allclose(a, G.sum(1)) + np.testing.assert_allclose(b, G.sum(0)) + + +def test_generalized_conditional_gradient(): + + n_bins = 100 # nb bins + np.random.seed(0) + # bin positions + x = np.arange(n_bins, dtype=np.float64) + + # Gaussian distributions + a = ot.datasets.get_1D_gauss(n_bins, m=20, s=5) # m= mean, s= std + b = ot.datasets.get_1D_gauss(n_bins, m=60, s=10) + + # loss matrix + M = ot.dist(x.reshape((n_bins, 1)), x.reshape((n_bins, 1))) + M /= M.max() + + def f(G): + return 0.5 * np.sum(G**2) + + def df(G): + return G + + reg1 = 1e-3 + reg2 = 1e-1 + + G, log = ot.optim.gcg(a, b, M, reg1, reg2, f, df, verbose=True, log=True) + + np.testing.assert_allclose(a, G.sum(1), atol=1e-05) + np.testing.assert_allclose(b, G.sum(0), atol=1e-05) diff --git a/test/test_ot.py b/test/test_ot.py new file mode 100644 index 0000000..acd8718 --- /dev/null +++ b/test/test_ot.py @@ -0,0 +1,102 @@ +"""Tests for main module ot """ + +# Author: Remi Flamary <remi.flamary@unice.fr> +# +# License: MIT License + +import numpy as np +import ot + + +def test_doctest(): + + import doctest + + # test lp solver + doctest.testmod(ot.lp, verbose=True) + + # test bregman solver + doctest.testmod(ot.bregman, verbose=True) + + +def test_emd_emd2(): + # test emd and emd2 for simple identity + n = 100 + rng = np.random.RandomState(0) + + x = rng.randn(n, 2) + u = ot.utils.unif(n) + + M = ot.dist(x, x) + + G = ot.emd(u, u, M) + + # check G is identity + np.testing.assert_allclose(G, np.eye(n) / n) + # check constratints + np.testing.assert_allclose(u, G.sum(1)) # cf convergence sinkhorn + np.testing.assert_allclose(u, G.sum(0)) # cf convergence sinkhorn + + w = ot.emd2(u, u, M) + # check loss=0 + np.testing.assert_allclose(w, 0) + + +def test_emd_empty(): + # test emd and emd2 for simple identity + n = 100 + rng = np.random.RandomState(0) + + x = rng.randn(n, 2) + u = ot.utils.unif(n) + + M = ot.dist(x, x) + + G = ot.emd([], [], M) + + # check G is identity + np.testing.assert_allclose(G, np.eye(n) / n) + # check constratints + np.testing.assert_allclose(u, G.sum(1)) # cf convergence sinkhorn + np.testing.assert_allclose(u, G.sum(0)) # cf convergence sinkhorn + + w = ot.emd2([], [], M) + # check loss=0 + np.testing.assert_allclose(w, 0) + + +def test_emd2_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, 20) + 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') + + np.testing.assert_allclose(emd1, emdn) diff --git a/test/test_plot.py b/test/test_plot.py new file mode 100644 index 0000000..f7debee --- /dev/null +++ b/test/test_plot.py @@ -0,0 +1,49 @@ +"""Tests for module plot for visualization """ + +# Author: Remi Flamary <remi.flamary@unice.fr> +# +# License: MIT License + +import numpy as np +import matplotlib +matplotlib.use('Agg') + + +def test_plot1D_mat(): + + import ot + + n_bins = 100 # nb bins + + # bin positions + x = np.arange(n_bins, dtype=np.float64) + + # Gaussian distributions + a = ot.datasets.get_1D_gauss(n_bins, m=20, s=5) # m= mean, s= std + b = ot.datasets.get_1D_gauss(n_bins, m=60, s=10) + + # loss matrix + M = ot.dist(x.reshape((n_bins, 1)), x.reshape((n_bins, 1))) + M /= M.max() + + ot.plot.plot1D_mat(a, b, M, 'Cost matrix M') + + +def test_plot2D_samples_mat(): + + import ot + + n_bins = 50 # 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_bins, mu_s, cov_s) + xt = ot.datasets.get_2D_samples_gauss(n_bins, mu_t, cov_t) + + G = 1.0 * (np.random.rand(n_bins, n_bins) < 0.01) + + ot.plot.plot2D_samples_mat(xs, xt, G, thr=1e-5) diff --git a/test/test_utils.py b/test/test_utils.py new file mode 100644 index 0000000..1bd37cd --- /dev/null +++ b/test/test_utils.py @@ -0,0 +1,125 @@ +"""Tests for module utils for timing and parallel computation """ + +# Author: Remi Flamary <remi.flamary@unice.fr> +# +# License: MIT License + + +import ot +import numpy as np + + +def test_parmap(): + + n = 100 + + def f(i): + return 1.0 * i * i + + a = np.arange(n) + + l1 = list(map(f, a)) + + l2 = list(ot.utils.parmap(f, a)) + + np.testing.assert_allclose(l1, l2) + + +def test_tic_toc(): + + import time + + ot.tic() + time.sleep(0.5) + t = ot.toc() + t2 = ot.toq() + + # test timing + np.testing.assert_allclose(0.5, t, rtol=1e-2, atol=1e-2) + + # test toc vs toq + np.testing.assert_allclose(t, t2, rtol=1e-2, atol=1e-2) + + +def test_kernel(): + + n = 100 + + x = np.random.randn(n, 2) + + K = ot.utils.kernel(x, x) + + # gaussian kernel has ones on the diagonal + np.testing.assert_allclose(np.diag(K), np.ones(n)) + + +def test_unif(): + + n = 100 + + u = ot.unif(n) + + np.testing.assert_allclose(1, np.sum(u)) + + +def test_dist(): + + n = 100 + + x = np.random.randn(n, 2) + + D = np.zeros((n, n)) + for i in range(n): + for j in range(n): + D[i, j] = np.sum(np.square(x[i, :] - x[j, :])) + + D2 = ot.dist(x, x) + D3 = ot.dist(x) + + # dist shoul return squared euclidean + np.testing.assert_allclose(D, D2) + np.testing.assert_allclose(D, D3) + + +def test_dist0(): + + n = 100 + M = ot.utils.dist0(n, method='lin_square') + + # dist0 default to linear sampling with quadratic loss + np.testing.assert_allclose(M[0, -1], (n - 1) * (n - 1)) + + +def test_dots(): + + n1, n2, n3, n4 = 100, 50, 200, 100 + + A = np.random.randn(n1, n2) + B = np.random.randn(n2, n3) + C = np.random.randn(n3, n4) + + X1 = ot.utils.dots(A, B, C) + + X2 = A.dot(B.dot(C)) + + np.testing.assert_allclose(X1, X2) + + +def test_clean_zeros(): + + n = 100 + nz = 50 + nz2 = 20 + u1 = ot.unif(n) + u1[:nz] = 0 + u1 = u1 / u1.sum() + u2 = ot.unif(n) + u2[:nz2] = 0 + u2 = u2 / u2.sum() + + M = ot.utils.dist0(n) + + a, b, M2 = ot.utils.clean_zeros(u1, u2, M) + + assert len(a) == n - nz + assert len(b) == n - nz2 |