/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #if (defined(__GNUC__) && !defined(__clang__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #include "xtensor/generators/xrandom.hpp" #pragma GCC diagnostic pop #else #include "xtensor/generators/xrandom.hpp" #endif #include "xtensor/containers/xarray.hpp" #include "xtensor/misc/xset_operation.hpp" #include "xtensor/views/xview.hpp" #include "test_common_macros.hpp" namespace xt { TEST(xrandom, random) { auto r = random::rand({3, 3}); xarray a = r; xarray b = r; xarray c = r; ASSERT_NE(a(0, 0), a(0, 1)); ASSERT_NE(a, b); ASSERT_NE(a, c); xarray other_rand = random::rand({3, 3}); ASSERT_NE(a, other_rand); random::seed(0); auto same_d_a = random::rand({3, 3}); xarray same_a = same_d_a; random::seed(0); auto same_d_b = random::rand({3, 3}); xarray same_b = same_d_b; ASSERT_EQ(same_a, same_b); // check that it compiles and generates same random numbers for the same seed random::seed(0); xarray q = random::randint({3, 3}); random::seed(0); xarray same_q = random::randint({3, 3}); ASSERT_EQ(q, same_q); random::seed(0); xarray binom = random::binomial({3, 3}); random::seed(0); xarray same_binom = random::binomial({3, 3}); ASSERT_EQ(binom, same_binom); random::seed(0); xarray geom = random::geometric({3, 3}); random::seed(0); xarray same_geom = random::geometric({3, 3}); ASSERT_EQ(geom, same_geom); random::seed(0); xarray neg_binom = random::negative_binomial({3, 3}); random::seed(0); xarray same_neg_binom = random::negative_binomial({3, 3}); ASSERT_EQ(neg_binom, same_neg_binom); random::seed(0); xarray poisson = random::poisson({3, 3}); random::seed(0); xarray same_poisson = random::poisson({3, 3}); ASSERT_EQ(poisson, same_poisson); random::seed(0); xarray exp = random::exponential({3, 3}); random::seed(0); xarray same_exp = random::exponential({3, 3}); ASSERT_EQ(exp, same_exp); random::seed(0); xarray gamma = random::gamma({3, 3}); random::seed(0); xarray same_gamma = random::gamma({3, 3}); ASSERT_EQ(gamma, same_gamma); random::seed(0); xarray weibull = random::weibull({3, 3}); random::seed(0); xarray same_weibull = random::weibull({3, 3}); ASSERT_EQ(weibull, same_weibull); random::seed(0); xarray extreme_val = random::extreme_value({3, 3}); random::seed(0); xarray same_extreme_val = random::extreme_value({3, 3}); ASSERT_EQ(extreme_val, same_extreme_val); random::seed(0); xarray lnormal = random::lognormal({3, 3}); random::seed(0); xarray same_lnormal = random::lognormal({3, 3}); ASSERT_EQ(lnormal, same_lnormal); random::seed(0); xarray xsqr = random::chi_squared({3, 3}); random::seed(0); xarray same_xsqr = random::chi_squared({3, 3}); ASSERT_EQ(xsqr, same_xsqr); random::seed(0); xarray cauchy = random::cauchy({3, 3}); random::seed(0); xarray same_cauchy = random::cauchy({3, 3}); ASSERT_EQ(cauchy, same_cauchy); random::seed(0); xarray fisher_f = random::fisher_f({3, 3}); random::seed(0); xarray same_fisher_f = random::fisher_f({3, 3}); ASSERT_EQ(fisher_f, same_fisher_f); random::seed(0); xarray student_t = random::student_t({3, 3}); random::seed(0); xarray same_student_t = random::student_t({3, 3}); ASSERT_EQ(student_t, same_student_t); // checking if internal state needs reset auto n_dist = random::randn({3, 3}); xarray p1 = n_dist; xarray p2 = n_dist; xarray p3 = n_dist; ASSERT_NE(p1, p2); ASSERT_NE(p1, p3); } TEST(xrandom, choice) { xarray a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; xt::random::seed(42); auto ac1 = xt::random::choice(a, 5, false); auto ac2 = xt::random::choice(a, 5, false); xt::random::seed(42); auto ac3 = xt::random::choice(a, 5, false); ASSERT_EQ(ac1, ac3); ASSERT_NE(ac1, ac2); xt::random::seed(42); auto acr1 = xt::random::choice(a, 5, true); auto acr2 = xt::random::choice(a, 5, true); xt::random::seed(42); auto acr3 = xt::random::choice(a, 5, true); ASSERT_EQ(acr1, acr3); ASSERT_NE(acr1, acr2); } TEST(xrandom, weighted_choice) { xarray a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; xarray w = {1, 0, 2, 0, 1, 0, 1, 0, 2, 0, 1, 0}; for (bool replace : {true, false}) { xt::random::seed(42); auto ac1 = xt::random::choice(a, 6, w, replace); auto ac2 = xt::random::choice(a, 6, w, replace); xt::random::seed(42); auto ac3 = xt::random::choice(a, 6, w, replace); static_assert( std::is_same::value, "Elements must be same type" ); ASSERT_EQ(ac1, ac3); ASSERT_NE(ac1, ac2); ASSERT_TRUE(all(isin(ac1, a))); ASSERT_TRUE(all(equal(ac1 % 2, 1))); } } TEST(xrandom, shuffle) { xarray a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; xt::random::shuffle(a); EXPECT_FALSE(std::is_sorted(a.begin(), a.end())); xarray b = a; b.resize({b.size(), 1}); xt::random::seed(42); xt::random::shuffle(a); xt::random::seed(42); xt::random::shuffle(b); b.resize({b.size()}); EXPECT_EQ(a, b); a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; a.reshape({3, 4}); auto ar = a; xt::random::seed(123); // Unfortunately MSVC, OS X, and Clang on Linux seem to produce different // shuffles even though the generated integer sequence should be the same ... #if defined(__linux__) && (!defined(__clang__) || (__clang_major__ < 11)) xt::random::shuffle(a); EXPECT_EQ(xt::view(ar, keep(0, 1, 2)), a); xt::random::shuffle(a); EXPECT_EQ(xt::view(ar, keep(1, 2, 0)), a); xt::random::shuffle(a); EXPECT_EQ(xt::view(ar, keep(0, 2, 1)), a); xt::random::shuffle(a); EXPECT_EQ(xt::view(ar, keep(0, 1, 2)), a); xt::random::shuffle(a); EXPECT_EQ(xt::view(ar, keep(1, 0, 2)), a); xt::random::shuffle(a); EXPECT_EQ(xt::view(ar, keep(1, 2, 0)), a); xt::random::shuffle(a); EXPECT_EQ(xt::view(ar, keep(2, 1, 0)), a); xt::random::shuffle(a); xt::random::shuffle(a); xt::random::shuffle(a); xt::random::shuffle(a); xt::random::shuffle(a); xt::random::shuffle(a); EXPECT_EQ(xt::view(ar, keep(0, 2, 1)), a); #else xt::random::shuffle(a); xt::random::shuffle(a); EXPECT_FALSE(std::is_sorted(a.begin(), a.end())); #endif } TEST(xrandom, poisson_geometric_default_type) { // poisson and geometric have no parameter from which T can be deduced, // so they require a default T (= int) to be callable without explicit template arg. auto p = random::poisson({3, 3}, 1.0); static_assert(std::is_same::value, "poisson default T must be int"); auto g = random::geometric({3, 3}, 0.5); static_assert(std::is_same::value, "geometric default T must be int"); auto p2 = random::poisson({3, 3}); static_assert(std::is_same::value, "poisson default T must be int"); } TEST(xrandom, permutation) { xt::random::seed(123); auto r1 = xt::random::permutation(12); xt::random::seed(123); xtensor a1 = arange(12); xtensor ac1 = a1; xt::random::shuffle(a1); EXPECT_EQ(a1, r1); EXPECT_NE(r1, ac1); xt::random::seed(123); auto r2 = xt::random::permutation(ac1); EXPECT_EQ(a1, r2); } }