1 /***************************************************************************
2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht          *
3 * Copyright (c) QuantStack                                                 *
4 *                                                                          *
5 * Distributed under the terms of the BSD 3-Clause License.                 *
6 *                                                                          *
7 * The full license is in the file LICENSE, distributed with this software. *
8 ****************************************************************************/
9 
10 #include <type_traits>
11 
12 #include "test_common_macros.hpp"
13 #include "test_common_macros.hpp"
14 #if (defined(__GNUC__) && !defined(__clang__))
15 #pragma GCC diagnostic push
16 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
17 #include "xtensor/xrandom.hpp"
18 #pragma GCC diagnostic pop
19 #else
20 #include "xtensor/xrandom.hpp"
21 #endif
22 #include "xtensor/xarray.hpp"
23 #include "xtensor/xview.hpp"
24 #include "xtensor/xset_operation.hpp"
25 
26 namespace xt
27 {
TEST(xrandom,random)28     TEST(xrandom, random)
29     {
30         auto r = random::rand<double>({3, 3});
31         xarray<double> a = r;
32         xarray<double> b = r;
33         xarray<double> c = r;
34 
35         ASSERT_NE(a(0, 0), a(0, 1));
36         ASSERT_NE(a, b);
37         ASSERT_NE(a, c);
38 
39         xarray<double> other_rand = random::rand<double>({3, 3});
40         ASSERT_NE(a, other_rand);
41 
42         random::seed(0);
43         auto same_d_a = random::rand<double>({3, 3});
44         xarray<double> same_a = same_d_a;
45 
46         random::seed(0);
47         auto same_d_b = random::rand<double>({3, 3});
48         xarray<double> same_b = same_d_b;
49 
50         ASSERT_EQ(same_a, same_b);
51 
52         // check that it compiles and generates same random numbers for the same seed
53         random::seed(0);
54         xarray<int> q = random::randint<int>({3, 3});
55         random::seed(0);
56         xarray<int> same_q = random::randint<int>({3, 3});
57         ASSERT_EQ(q, same_q);
58 
59         random::seed(0);
60         xarray<int> binom = random::binomial<int>({3, 3});
61         random::seed(0);
62         xarray<int> same_binom = random::binomial<int>({3, 3});
63         ASSERT_EQ(binom, same_binom);
64 
65         random::seed(0);
66         xarray<int> geom = random::geometric<int>({3, 3});
67         random::seed(0);
68         xarray<int> same_geom = random::geometric<int>({3, 3});
69         ASSERT_EQ(geom, same_geom);
70 
71         random::seed(0);
72         xarray<int> neg_binom = random::negative_binomial<int>({3, 3});
73         random::seed(0);
74         xarray<int> same_neg_binom = random::negative_binomial<int>({3, 3});
75         ASSERT_EQ(neg_binom, same_neg_binom);
76 
77         random::seed(0);
78         xarray<int> poisson = random::poisson<int>({3, 3});
79         random::seed(0);
80         xarray<int> same_poisson = random::poisson<int>({3, 3});
81         ASSERT_EQ(poisson, same_poisson);
82 
83         random::seed(0);
84         xarray<double> exp = random::exponential<double>({3, 3});
85         random::seed(0);
86         xarray<double> same_exp = random::exponential<double>({3, 3});
87         ASSERT_EQ(exp, same_exp);
88 
89         random::seed(0);
90         xarray<double> gamma = random::gamma<double>({3, 3});
91         random::seed(0);
92         xarray<double> same_gamma = random::gamma<double>({3, 3});
93         ASSERT_EQ(gamma, same_gamma);
94 
95         random::seed(0);
96         xarray<double> weibull = random::weibull<double>({3, 3});
97         random::seed(0);
98         xarray<double> same_weibull = random::weibull<double>({3, 3});
99         ASSERT_EQ(weibull, same_weibull);
100 
101         random::seed(0);
102         xarray<double> extreme_val = random::extreme_value<double>({3, 3});
103         random::seed(0);
104         xarray<double> same_extreme_val = random::extreme_value<double>({3, 3});
105         ASSERT_EQ(extreme_val, same_extreme_val);
106 
107         random::seed(0);
108         xarray<double> lnormal = random::lognormal<double>({3, 3});
109         random::seed(0);
110         xarray<double> same_lnormal = random::lognormal<double>({3, 3});
111         ASSERT_EQ(lnormal, same_lnormal);
112 
113         random::seed(0);
114         xarray<double> xsqr = random::chi_squared<double>({3, 3});
115         random::seed(0);
116         xarray<double> same_xsqr = random::chi_squared<double>({3, 3});
117         ASSERT_EQ(xsqr, same_xsqr);
118 
119         random::seed(0);
120         xarray<double> cauchy = random::cauchy<double>({3, 3});
121         random::seed(0);
122         xarray<double> same_cauchy = random::cauchy<double>({3, 3});
123         ASSERT_EQ(cauchy, same_cauchy);
124 
125         random::seed(0);
126         xarray<double> fisher_f = random::fisher_f<double>({3, 3});
127         random::seed(0);
128         xarray<double> same_fisher_f = random::fisher_f<double>({3, 3});
129         ASSERT_EQ(fisher_f, same_fisher_f);
130 
131         random::seed(0);
132         xarray<double> student_t = random::student_t<double>({3, 3});
133         random::seed(0);
134         xarray<double> same_student_t = random::student_t<double>({3, 3});
135         ASSERT_EQ(student_t, same_student_t);
136 
137         // checking if internal state needs reset
138         auto n_dist = random::randn<double>({3, 3});
139         xarray<double> p1 = n_dist;
140         xarray<double> p2 = n_dist;
141         xarray<double> p3 = n_dist;
142         ASSERT_NE(p1, p2);
143         ASSERT_NE(p1, p3);
144     }
145 
TEST(xrandom,choice)146     TEST(xrandom, choice)
147     {
148         xarray<double> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
149         xt::random::seed(42);
150         auto ac1 = xt::random::choice(a, 5, false);
151         auto ac2 = xt::random::choice(a, 5, false);
152         xt::random::seed(42);
153         auto ac3 = xt::random::choice(a, 5, false);
154         ASSERT_EQ(ac1, ac3);
155         ASSERT_NE(ac1, ac2);
156 
157         xt::random::seed(42);
158         auto acr1 = xt::random::choice(a, 5, true);
159         auto acr2 = xt::random::choice(a, 5, true);
160         xt::random::seed(42);
161         auto acr3 = xt::random::choice(a, 5, true);
162         ASSERT_EQ(acr1, acr3);
163         ASSERT_NE(acr1, acr2);
164     }
165 
TEST(xrandom,weighted_choice)166     TEST(xrandom, weighted_choice)
167     {
168         xarray<int> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
169         xarray<double> w = {1, 0, 2, 0, 1, 0, 1, 0, 2, 0, 1, 0};
170 
171         for(bool replace : {true, false}) {
172             xt::random::seed(42);
173             auto ac1 = xt::random::choice(a, 6, w, replace);
174             auto ac2 = xt::random::choice(a, 6, w, replace);
175             xt::random::seed(42);
176             auto ac3 = xt::random::choice(a, 6, w, replace);
177             static_assert(std::is_same<decltype(a)::value_type, decltype(ac1)::value_type>::value,
178                           "Elements must be same type");
179             ASSERT_EQ(ac1, ac3);
180             ASSERT_NE(ac1, ac2);
181             ASSERT_TRUE(all(isin(ac1, a)));
182             ASSERT_TRUE(all(equal(ac1 % 2, 1)));
183         }
184     }
185 
TEST(xrandom,shuffle)186     TEST(xrandom, shuffle)
187     {
188         xarray<double> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
189         xt::random::shuffle(a);
190         EXPECT_FALSE(std::is_sorted(a.begin(), a.end()));
191 
192         xarray<double> b = a;
193         b.resize({b.size(), 1});
194         xt::random::seed(42);
195         xt::random::shuffle(a);
196         xt::random::seed(42);
197         xt::random::shuffle(b);
198         b.resize({b.size()});
199         EXPECT_EQ(a, b);
200 
201         a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
202         a.reshape({3, 4});
203         auto ar = a;
204 
205         xt::random::seed(123);
206         // Unfortunately MSVC, OS X, and Clang on Linux seem to produce different
207         // shuffles even though the generated integer sequence should be the same ...
208 #if defined(__linux__) && (!defined(__clang__) || (__clang_major__ < 11))
209         xt::random::shuffle(a);
210         EXPECT_EQ(xt::view(ar, keep(0, 1, 2)), a);
211         xt::random::shuffle(a);
212         EXPECT_EQ(xt::view(ar, keep(1, 2, 0)), a);
213         xt::random::shuffle(a);
214         EXPECT_EQ(xt::view(ar, keep(0, 2, 1)), a);
215         xt::random::shuffle(a);
216         EXPECT_EQ(xt::view(ar, keep(0, 1, 2)), a);
217         xt::random::shuffle(a);
218         EXPECT_EQ(xt::view(ar, keep(1, 0, 2)), a);
219         xt::random::shuffle(a);
220         EXPECT_EQ(xt::view(ar, keep(1, 2, 0)), a);
221         xt::random::shuffle(a);
222         EXPECT_EQ(xt::view(ar, keep(2, 1, 0)), a);
223         xt::random::shuffle(a);
224         xt::random::shuffle(a);
225         xt::random::shuffle(a);
226         xt::random::shuffle(a);
227         xt::random::shuffle(a);
228         xt::random::shuffle(a);
229         EXPECT_EQ(xt::view(ar, keep(0, 2, 1)), a);
230 #else
231         xt::random::shuffle(a);
232         xt::random::shuffle(a);
233         EXPECT_FALSE(std::is_sorted(a.begin(), a.end()));
234 #endif
235 
236     }
237 
TEST(xrandom,permutation)238     TEST(xrandom, permutation)
239     {
240         xt::random::seed(123);
241         auto r1 = xt::random::permutation(12);
242         xt::random::seed(123);
243         xtensor<int, 1> a1 = arange<int>(12);
244         xtensor<int, 1> ac1 = a1;
245         xt::random::shuffle(a1);
246         EXPECT_EQ(a1, r1);
247         EXPECT_NE(r1, ac1);
248 
249         xt::random::seed(123);
250         auto r2 = xt::random::permutation(ac1);
251         EXPECT_EQ(a1, r2);
252     }
253 }
254