/***************************************************************************
* 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);
}
}