xrandom.hpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  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. * @brief functions to obtain xgenerators generating random numbers with given shape
  11. */
  12. #ifndef XTENSOR_RANDOM_HPP
  13. #define XTENSOR_RANDOM_HPP
  14. #include <algorithm>
  15. #include <functional>
  16. #include <random>
  17. #include <type_traits>
  18. #include <utility>
  19. #include <xtl/xspan.hpp>
  20. #include "xbuilder.hpp"
  21. #include "xgenerator.hpp"
  22. #include "xindex_view.hpp"
  23. #include "xmath.hpp"
  24. #include "xtensor.hpp"
  25. #include "xtensor_config.hpp"
  26. #include "xview.hpp"
  27. namespace xt
  28. {
  29. /*********************
  30. * Random generators *
  31. *********************/
  32. namespace random
  33. {
  34. using default_engine_type = std::mt19937;
  35. using seed_type = default_engine_type::result_type;
  36. default_engine_type& get_default_random_engine();
  37. void seed(seed_type seed);
  38. template <class T, class S, class E = random::default_engine_type>
  39. auto rand(const S& shape, T lower = 0, T upper = 1, E& engine = random::get_default_random_engine());
  40. template <class T, class S, class E = random::default_engine_type>
  41. auto randint(
  42. const S& shape,
  43. T lower = 0,
  44. T upper = (std::numeric_limits<T>::max)(),
  45. E& engine = random::get_default_random_engine()
  46. );
  47. template <class T, class S, class E = random::default_engine_type>
  48. auto randn(const S& shape, T mean = 0, T std_dev = 1, E& engine = random::get_default_random_engine());
  49. template <class T, class S, class D = double, class E = random::default_engine_type>
  50. auto
  51. binomial(const S& shape, T trials = 1, D prob = 0.5, E& engine = random::get_default_random_engine());
  52. template <class T, class S, class D = double, class E = random::default_engine_type>
  53. auto geometric(const S& shape, D prob = 0.5, E& engine = random::get_default_random_engine());
  54. template <class T, class S, class D = double, class E = random::default_engine_type>
  55. auto
  56. negative_binomial(const S& shape, T k = 1, D prob = 0.5, E& engine = random::get_default_random_engine());
  57. template <class T, class S, class D = double, class E = random::default_engine_type>
  58. auto poisson(const S& shape, D rate = 1.0, E& engine = random::get_default_random_engine());
  59. template <class T, class S, class E = random::default_engine_type>
  60. auto exponential(const S& shape, T rate = 1.0, E& engine = random::get_default_random_engine());
  61. template <class T, class S, class E = random::default_engine_type>
  62. auto
  63. gamma(const S& shape, T alpha = 1.0, T beta = 1.0, E& engine = random::get_default_random_engine());
  64. template <class T, class S, class E = random::default_engine_type>
  65. auto weibull(const S& shape, T a = 1.0, T b = 1.0, E& engine = random::get_default_random_engine());
  66. template <class T, class S, class E = random::default_engine_type>
  67. auto
  68. extreme_value(const S& shape, T a = 0.0, T b = 1.0, E& engine = random::get_default_random_engine());
  69. template <class T, class S, class E = random::default_engine_type>
  70. auto
  71. lognormal(const S& shape, T mean = 0, T std_dev = 1, E& engine = random::get_default_random_engine());
  72. template <class T, class S, class E = random::default_engine_type>
  73. auto chi_squared(const S& shape, T deg = 1.0, E& engine = random::get_default_random_engine());
  74. template <class T, class S, class E = random::default_engine_type>
  75. auto cauchy(const S& shape, T a = 0.0, T b = 1.0, E& engine = random::get_default_random_engine());
  76. template <class T, class S, class E = random::default_engine_type>
  77. auto fisher_f(const S& shape, T m = 1.0, T n = 1.0, E& engine = random::get_default_random_engine());
  78. template <class T, class S, class E = random::default_engine_type>
  79. auto student_t(const S& shape, T n = 1.0, E& engine = random::get_default_random_engine());
  80. template <class T, class I, std::size_t L, class E = random::default_engine_type>
  81. auto
  82. rand(const I (&shape)[L], T lower = 0, T upper = 1, E& engine = random::get_default_random_engine());
  83. template <class T, class I, std::size_t L, class E = random::default_engine_type>
  84. auto randint(
  85. const I (&shape)[L],
  86. T lower = 0,
  87. T upper = (std::numeric_limits<T>::max)(),
  88. E& engine = random::get_default_random_engine()
  89. );
  90. template <class T, class I, std::size_t L, class E = random::default_engine_type>
  91. auto
  92. randn(const I (&shape)[L], T mean = 0, T std_dev = 1, E& engine = random::get_default_random_engine());
  93. template <class T, class I, std::size_t L, class D = double, class E = random::default_engine_type>
  94. auto
  95. binomial(const I (&shape)[L], T trials = 1, D prob = 0.5, E& engine = random::get_default_random_engine());
  96. template <class T, class I, std::size_t L, class D = double, class E = random::default_engine_type>
  97. auto geometric(const I (&shape)[L], D prob = 0.5, E& engine = random::get_default_random_engine());
  98. template <class T, class I, std::size_t L, class D = double, class E = random::default_engine_type>
  99. auto negative_binomial(
  100. const I (&shape)[L],
  101. T k = 1,
  102. D prob = 0.5,
  103. E& engine = random::get_default_random_engine()
  104. );
  105. template <class T, class I, std::size_t L, class D = double, class E = random::default_engine_type>
  106. auto poisson(const I (&shape)[L], D rate = 1.0, E& engine = random::get_default_random_engine());
  107. template <class T, class I, std::size_t L, class E = random::default_engine_type>
  108. auto exponential(const I (&shape)[L], T rate = 1.0, E& engine = random::get_default_random_engine());
  109. template <class T, class I, std::size_t L, class E = random::default_engine_type>
  110. auto
  111. gamma(const I (&shape)[L], T alpha = 1.0, T beta = 1.0, E& engine = random::get_default_random_engine());
  112. template <class T, class I, std::size_t L, class E = random::default_engine_type>
  113. auto
  114. weibull(const I (&shape)[L], T a = 1.0, T b = 1.0, E& engine = random::get_default_random_engine());
  115. template <class T, class I, std::size_t L, class E = random::default_engine_type>
  116. auto
  117. extreme_value(const I (&shape)[L], T a = 0.0, T b = 1.0, E& engine = random::get_default_random_engine());
  118. template <class T, class I, std::size_t L, class E = random::default_engine_type>
  119. auto lognormal(
  120. const I (&shape)[L],
  121. T mean = 0.0,
  122. T std_dev = 1.0,
  123. E& engine = random::get_default_random_engine()
  124. );
  125. template <class T, class I, std::size_t L, class E = random::default_engine_type>
  126. auto chi_squared(const I (&shape)[L], T deg = 1.0, E& engine = random::get_default_random_engine());
  127. template <class T, class I, std::size_t L, class E = random::default_engine_type>
  128. auto cauchy(const I (&shape)[L], T a = 0.0, T b = 1.0, E& engine = random::get_default_random_engine());
  129. template <class T, class I, std::size_t L, class E = random::default_engine_type>
  130. auto
  131. fisher_f(const I (&shape)[L], T m = 1.0, T n = 1.0, E& engine = random::get_default_random_engine());
  132. template <class T, class I, std::size_t L, class E = random::default_engine_type>
  133. auto student_t(const I (&shape)[L], T n = 1.0, E& engine = random::get_default_random_engine());
  134. template <class T, class E = random::default_engine_type>
  135. void shuffle(xexpression<T>& e, E& engine = random::get_default_random_engine());
  136. template <class T, class E = random::default_engine_type>
  137. std::enable_if_t<xtl::is_integral<T>::value, xtensor<T, 1>>
  138. permutation(T e, E& engine = random::get_default_random_engine());
  139. template <class T, class E = random::default_engine_type>
  140. std::enable_if_t<is_xexpression<std::decay_t<T>>::value, std::decay_t<T>>
  141. permutation(T&& e, E& engine = random::get_default_random_engine());
  142. template <class T, class E = random::default_engine_type>
  143. xtensor<typename T::value_type, 1> choice(
  144. const xexpression<T>& e,
  145. std::size_t n,
  146. bool replace = true,
  147. E& engine = random::get_default_random_engine()
  148. );
  149. template <class T, class W, class E = random::default_engine_type>
  150. xtensor<typename T::value_type, 1> choice(
  151. const xexpression<T>& e,
  152. std::size_t n,
  153. const xexpression<W>& weights,
  154. bool replace = true,
  155. E& engine = random::get_default_random_engine()
  156. );
  157. }
  158. namespace detail
  159. {
  160. template <class T, class E, class D>
  161. struct random_impl
  162. {
  163. using value_type = T;
  164. random_impl(E& engine, D&& dist)
  165. : m_engine(engine)
  166. , m_dist(std::move(dist))
  167. {
  168. }
  169. template <class... Args>
  170. inline value_type operator()(Args...) const
  171. {
  172. return m_dist(m_engine);
  173. }
  174. template <class It>
  175. inline value_type element(It, It) const
  176. {
  177. return m_dist(m_engine);
  178. }
  179. template <class EX>
  180. inline void assign_to(xexpression<EX>& e) const noexcept
  181. {
  182. // Note: we're not going row/col major here
  183. auto& ed = e.derived_cast();
  184. for (auto&& el : ed.storage())
  185. {
  186. el = m_dist(m_engine);
  187. }
  188. }
  189. private:
  190. E& m_engine;
  191. mutable D m_dist;
  192. };
  193. }
  194. namespace random
  195. {
  196. /**
  197. * Returns a reference to the default random number engine
  198. */
  199. inline default_engine_type& get_default_random_engine()
  200. {
  201. static default_engine_type mt;
  202. return mt;
  203. }
  204. /**
  205. * Seeds the default random number generator with @p seed
  206. * @param seed The seed
  207. */
  208. inline void seed(seed_type seed)
  209. {
  210. get_default_random_engine().seed(seed);
  211. }
  212. /**
  213. * xexpression with specified @p shape containing uniformly distributed random numbers
  214. * in the interval from @p lower to @p upper, excluding upper.
  215. *
  216. * Numbers are drawn from @c std::uniform_real_distribution.
  217. *
  218. * @param shape shape of resulting xexpression
  219. * @param lower lower bound
  220. * @param upper upper bound
  221. * @param engine random number engine
  222. * @tparam T number type to use
  223. */
  224. template <class T, class S, class E>
  225. inline auto rand(const S& shape, T lower, T upper, E& engine)
  226. {
  227. std::uniform_real_distribution<T> dist(lower, upper);
  228. return detail::make_xgenerator(
  229. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  230. shape
  231. );
  232. }
  233. /**
  234. * xexpression with specified @p shape containing uniformly distributed
  235. * random integers in the interval from @p lower to @p upper, excluding upper.
  236. *
  237. * Numbers are drawn from @c std::uniform_int_distribution.
  238. *
  239. * @param shape shape of resulting xexpression
  240. * @param lower lower bound
  241. * @param upper upper bound
  242. * @param engine random number engine
  243. * @tparam T number type to use
  244. */
  245. template <class T, class S, class E>
  246. inline auto randint(const S& shape, T lower, T upper, E& engine)
  247. {
  248. std::uniform_int_distribution<T> dist(lower, T(upper - 1));
  249. return detail::make_xgenerator(
  250. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  251. shape
  252. );
  253. }
  254. /**
  255. * xexpression with specified @p shape containing numbers sampled from
  256. * the Normal (Gaussian) random number distribution with mean @p mean and
  257. * standard deviation @p std_dev.
  258. *
  259. * Numbers are drawn from @c std::normal_distribution.
  260. *
  261. * @param shape shape of resulting xexpression
  262. * @param mean mean of normal distribution
  263. * @param std_dev standard deviation of normal distribution
  264. * @param engine random number engine
  265. * @tparam T number type to use
  266. */
  267. template <class T, class S, class E>
  268. inline auto randn(const S& shape, T mean, T std_dev, E& engine)
  269. {
  270. std::normal_distribution<T> dist(mean, std_dev);
  271. return detail::make_xgenerator(
  272. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  273. shape
  274. );
  275. }
  276. /**
  277. * xexpression with specified @p shape containing numbers sampled from
  278. * the binomial random number distribution for @p trials trials with
  279. * probability of success equal to @p prob.
  280. *
  281. * Numbers are drawn from @c std::binomial_distribution.
  282. *
  283. * @param shape shape of resulting xexpression
  284. * @param trials number of Bernoulli trials
  285. * @param prob probability of success of each trial
  286. * @param engine random number engine
  287. * @tparam T number type to use
  288. */
  289. template <class T, class S, class D, class E>
  290. inline auto binomial(const S& shape, T trials, D prob, E& engine)
  291. {
  292. std::binomial_distribution<T> dist(trials, prob);
  293. return detail::make_xgenerator(
  294. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  295. shape
  296. );
  297. }
  298. /**
  299. * xexpression with specified @p shape containing numbers sampled from
  300. * a gemoetric random number distribution with
  301. * probability of success equal to @p prob for each of the Bernoulli trials.
  302. *
  303. * Numbers are drawn from @c std::geometric_distribution.
  304. *
  305. * @param shape shape of resulting xexpression
  306. * @param prob probability of success of each trial
  307. * @param engine random number engine
  308. * @tparam T number type to use
  309. */
  310. template <class T, class S, class D, class E>
  311. inline auto geometric(const S& shape, D prob, E& engine)
  312. {
  313. std::geometric_distribution<T> dist(prob);
  314. return detail::make_xgenerator(
  315. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  316. shape
  317. );
  318. }
  319. /**
  320. * xexpression with specified @p shape containing numbers sampled from
  321. * a negative binomial random number distribution (also known as Pascal distribution)
  322. * that returns the number of successes before @p k trials with probability of success
  323. * equal to @p prob for each of the Bernoulli trials.
  324. *
  325. * Numbers are drawn from @c std::negative_binomial_distribution.
  326. *
  327. * @param shape shape of resulting xexpression
  328. * @param k number of unsuccessful trials
  329. * @param prob probability of success of each trial
  330. * @param engine random number engine
  331. * @tparam T number type to use
  332. */
  333. template <class T, class S, class D, class E>
  334. inline auto negative_binomial(const S& shape, T k, D prob, E& engine)
  335. {
  336. std::negative_binomial_distribution<T> dist(k, prob);
  337. return detail::make_xgenerator(
  338. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  339. shape
  340. );
  341. }
  342. /**
  343. * xexpression with specified @p shape containing numbers sampled from
  344. * a Poisson random number distribution with rate @p rate
  345. *
  346. * Numbers are drawn from @c std::poisson_distribution.
  347. *
  348. * @param shape shape of resulting xexpression
  349. * @param rate rate of Poisson distribution
  350. * @param engine random number engine
  351. * @tparam T number type to use
  352. */
  353. template <class T, class S, class D, class E>
  354. inline auto poisson(const S& shape, D rate, E& engine)
  355. {
  356. std::poisson_distribution<T> dist(rate);
  357. return detail::make_xgenerator(
  358. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  359. shape
  360. );
  361. }
  362. /**
  363. * xexpression with specified @p shape containing numbers sampled from
  364. * a exponential random number distribution with rate @p rate
  365. *
  366. * Numbers are drawn from @c std::exponential_distribution.
  367. *
  368. * @param shape shape of resulting xexpression
  369. * @param rate rate of exponential distribution
  370. * @param engine random number engine
  371. * @tparam T number type to use
  372. */
  373. template <class T, class S, class E>
  374. inline auto exponential(const S& shape, T rate, E& engine)
  375. {
  376. std::exponential_distribution<T> dist(rate);
  377. return detail::make_xgenerator(
  378. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  379. shape
  380. );
  381. }
  382. /**
  383. * xexpression with specified @p shape containing numbers sampled from
  384. * a gamma random number distribution with shape @p alpha and scale @p beta
  385. *
  386. * Numbers are drawn from @c std::gamma_distribution.
  387. *
  388. * @param shape shape of resulting xexpression
  389. * @param alpha shape of the gamma distribution
  390. * @param beta scale of the gamma distribution
  391. * @param engine random number engine
  392. * @tparam T number type to use
  393. */
  394. template <class T, class S, class E>
  395. inline auto gamma(const S& shape, T alpha, T beta, E& engine)
  396. {
  397. std::gamma_distribution<T> dist(alpha, beta);
  398. return detail::make_xgenerator(
  399. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  400. shape
  401. );
  402. }
  403. /**
  404. * xexpression with specified @p shape containing numbers sampled from
  405. * a Weibull random number distribution with shape @p a and scale @p b
  406. *
  407. * Numbers are drawn from @c std::weibull_distribution.
  408. *
  409. * @param shape shape of resulting xexpression
  410. * @param a shape of the weibull distribution
  411. * @param b scale of the weibull distribution
  412. * @param engine random number engine
  413. * @tparam T number type to use
  414. */
  415. template <class T, class S, class E>
  416. inline auto weibull(const S& shape, T a, T b, E& engine)
  417. {
  418. std::weibull_distribution<T> dist(a, b);
  419. return detail::make_xgenerator(
  420. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  421. shape
  422. );
  423. }
  424. /**
  425. * xexpression with specified @p shape containing numbers sampled from
  426. * a extreme value random number distribution with shape @p a and scale @p b
  427. *
  428. * Numbers are drawn from @c std::extreme_value_distribution.
  429. *
  430. * @param shape shape of resulting xexpression
  431. * @param a shape of the extreme value distribution
  432. * @param b scale of the extreme value distribution
  433. * @param engine random number engine
  434. * @tparam T number type to use
  435. */
  436. template <class T, class S, class E>
  437. inline auto extreme_value(const S& shape, T a, T b, E& engine)
  438. {
  439. std::extreme_value_distribution<T> dist(a, b);
  440. return detail::make_xgenerator(
  441. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  442. shape
  443. );
  444. }
  445. /**
  446. * xexpression with specified @p shape containing numbers sampled from
  447. * the Log-Normal random number distribution with mean @p mean and
  448. * standard deviation @p std_dev.
  449. *
  450. * Numbers are drawn from @c std::lognormal_distribution.
  451. *
  452. * @param shape shape of resulting xexpression
  453. * @param mean mean of normal distribution
  454. * @param std_dev standard deviation of normal distribution
  455. * @param engine random number engine
  456. * @tparam T number type to use
  457. */
  458. template <class T, class S, class E>
  459. inline auto lognormal(const S& shape, T mean, T std_dev, E& engine)
  460. {
  461. std::lognormal_distribution<T> dist(mean, std_dev);
  462. return detail::make_xgenerator(
  463. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  464. shape
  465. );
  466. }
  467. /**
  468. * xexpression with specified @p shape containing numbers sampled from
  469. * the chi-squared random number distribution with @p deg degrees of freedom.
  470. *
  471. * Numbers are drawn from @c std::chi_squared_distribution.
  472. *
  473. * @param shape shape of resulting xexpression
  474. * @param deg degrees of freedom
  475. * @param engine random number engine
  476. * @tparam T number type to use
  477. */
  478. template <class T, class S, class E>
  479. inline auto chi_squared(const S& shape, T deg, E& engine)
  480. {
  481. std::chi_squared_distribution<T> dist(deg);
  482. return detail::make_xgenerator(
  483. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  484. shape
  485. );
  486. }
  487. /**
  488. * xexpression with specified @p shape containing numbers sampled from
  489. * a Cauchy random number distribution with peak @p a and scale @p b
  490. *
  491. * Numbers are drawn from @c std::cauchy_distribution.
  492. *
  493. * @param shape shape of resulting xexpression
  494. * @param a peak of the Cauchy distribution
  495. * @param b scale of the Cauchy distribution
  496. * @param engine random number engine
  497. * @tparam T number type to use
  498. */
  499. template <class T, class S, class E>
  500. inline auto cauchy(const S& shape, T a, T b, E& engine)
  501. {
  502. std::cauchy_distribution<T> dist(a, b);
  503. return detail::make_xgenerator(
  504. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  505. shape
  506. );
  507. }
  508. /**
  509. * xexpression with specified @p shape containing numbers sampled from
  510. * a Fisher-f random number distribution with numerator degrees of
  511. * freedom equal to @p m and denominator degrees of freedom equal to @p n
  512. *
  513. * Numbers are drawn from @c std::fisher_f_distribution.
  514. *
  515. * @param shape shape of resulting xexpression
  516. * @param m numerator degrees of freedom
  517. * @param n denominator degrees of freedom
  518. * @param engine random number engine
  519. * @tparam T number type to use
  520. */
  521. template <class T, class S, class E>
  522. inline auto fisher_f(const S& shape, T m, T n, E& engine)
  523. {
  524. std::fisher_f_distribution<T> dist(m, n);
  525. return detail::make_xgenerator(
  526. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  527. shape
  528. );
  529. }
  530. /**
  531. * xexpression with specified @p shape containing numbers sampled from
  532. * a Student-t random number distribution with degrees of
  533. * freedom equal to @p n
  534. *
  535. * Numbers are drawn from @c std::student_t_distribution.
  536. *
  537. * @param shape shape of resulting xexpression
  538. * @param n degrees of freedom
  539. * @param engine random number engine
  540. * @tparam T number type to use
  541. */
  542. template <class T, class S, class E>
  543. inline auto student_t(const S& shape, T n, E& engine)
  544. {
  545. std::student_t_distribution<T> dist(n);
  546. return detail::make_xgenerator(
  547. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  548. shape
  549. );
  550. }
  551. template <class T, class I, std::size_t L, class E>
  552. inline auto rand(const I (&shape)[L], T lower, T upper, E& engine)
  553. {
  554. std::uniform_real_distribution<T> dist(lower, upper);
  555. return detail::make_xgenerator(
  556. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  557. shape
  558. );
  559. }
  560. template <class T, class I, std::size_t L, class E>
  561. inline auto randint(const I (&shape)[L], T lower, T upper, E& engine)
  562. {
  563. std::uniform_int_distribution<T> dist(lower, T(upper - 1));
  564. return detail::make_xgenerator(
  565. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  566. shape
  567. );
  568. }
  569. template <class T, class I, std::size_t L, class E>
  570. inline auto randn(const I (&shape)[L], T mean, T std_dev, E& engine)
  571. {
  572. std::normal_distribution<T> dist(mean, std_dev);
  573. return detail::make_xgenerator(
  574. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  575. shape
  576. );
  577. }
  578. template <class T, class I, std::size_t L, class D, class E>
  579. inline auto binomial(const I (&shape)[L], T trials, D prob, E& engine)
  580. {
  581. std::binomial_distribution<T> dist(trials, prob);
  582. return detail::make_xgenerator(
  583. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  584. shape
  585. );
  586. }
  587. template <class T, class I, std::size_t L, class D, class E>
  588. inline auto geometric(const I (&shape)[L], D prob, E& engine)
  589. {
  590. std::geometric_distribution<T> dist(prob);
  591. return detail::make_xgenerator(
  592. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  593. shape
  594. );
  595. }
  596. template <class T, class I, std::size_t L, class D, class E>
  597. inline auto negative_binomial(const I (&shape)[L], T k, D prob, E& engine)
  598. {
  599. std::negative_binomial_distribution<T> dist(k, prob);
  600. return detail::make_xgenerator(
  601. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  602. shape
  603. );
  604. }
  605. template <class T, class I, std::size_t L, class D, class E>
  606. inline auto poisson(const I (&shape)[L], D rate, E& engine)
  607. {
  608. std::poisson_distribution<T> dist(rate);
  609. return detail::make_xgenerator(
  610. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  611. shape
  612. );
  613. }
  614. template <class T, class I, std::size_t L, class E>
  615. inline auto exponential(const I (&shape)[L], T rate, E& engine)
  616. {
  617. std::exponential_distribution<T> dist(rate);
  618. return detail::make_xgenerator(
  619. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  620. shape
  621. );
  622. }
  623. template <class T, class I, std::size_t L, class E>
  624. inline auto gamma(const I (&shape)[L], T alpha, T beta, E& engine)
  625. {
  626. std::gamma_distribution<T> dist(alpha, beta);
  627. return detail::make_xgenerator(
  628. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  629. shape
  630. );
  631. }
  632. template <class T, class I, std::size_t L, class E>
  633. inline auto weibull(const I (&shape)[L], T a, T b, E& engine)
  634. {
  635. std::weibull_distribution<T> dist(a, b);
  636. return detail::make_xgenerator(
  637. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  638. shape
  639. );
  640. }
  641. template <class T, class I, std::size_t L, class E>
  642. inline auto extreme_value(const I (&shape)[L], T a, T b, E& engine)
  643. {
  644. std::extreme_value_distribution<T> dist(a, b);
  645. return detail::make_xgenerator(
  646. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  647. shape
  648. );
  649. }
  650. template <class T, class I, std::size_t L, class E>
  651. inline auto lognormal(const I (&shape)[L], T mean, T std_dev, E& engine)
  652. {
  653. std::lognormal_distribution<T> dist(mean, std_dev);
  654. return detail::make_xgenerator(
  655. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  656. shape
  657. );
  658. }
  659. template <class T, class I, std::size_t L, class E>
  660. inline auto chi_squared(const I (&shape)[L], T deg, E& engine)
  661. {
  662. std::chi_squared_distribution<T> dist(deg);
  663. return detail::make_xgenerator(
  664. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  665. shape
  666. );
  667. }
  668. template <class T, class I, std::size_t L, class E>
  669. inline auto cauchy(const I (&shape)[L], T a, T b, E& engine)
  670. {
  671. std::cauchy_distribution<T> dist(a, b);
  672. return detail::make_xgenerator(
  673. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  674. shape
  675. );
  676. }
  677. template <class T, class I, std::size_t L, class E>
  678. inline auto fisher_f(const I (&shape)[L], T m, T n, E& engine)
  679. {
  680. std::fisher_f_distribution<T> dist(m, n);
  681. return detail::make_xgenerator(
  682. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  683. shape
  684. );
  685. }
  686. template <class T, class I, std::size_t L, class E>
  687. inline auto student_t(const I (&shape)[L], T n, E& engine)
  688. {
  689. std::student_t_distribution<T> dist(n);
  690. return detail::make_xgenerator(
  691. detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
  692. shape
  693. );
  694. }
  695. /**
  696. * Randomly shuffle elements inplace in xcontainer along first axis.
  697. * The order of sub-arrays is changed but their contents remain the same.
  698. *
  699. * @param e xcontainer to shuffle inplace
  700. * @param engine random number engine
  701. */
  702. template <class T, class E>
  703. void shuffle(xexpression<T>& e, E& engine)
  704. {
  705. T& de = e.derived_cast();
  706. if (de.dimension() == 1)
  707. {
  708. using size_type = typename T::size_type;
  709. auto first = de.begin();
  710. auto last = de.end();
  711. for (size_type i = std::size_t((last - first) - 1); i > 0; --i)
  712. {
  713. std::uniform_int_distribution<size_type> dist(0, i);
  714. auto j = dist(engine);
  715. using std::swap;
  716. swap(first[i], first[j]);
  717. }
  718. }
  719. else
  720. {
  721. using size_type = typename T::size_type;
  722. decltype(auto) buf = empty_like(view(de, 0));
  723. for (size_type i = de.shape()[0] - 1; i > 0; --i)
  724. {
  725. std::uniform_int_distribution<size_type> dist(0, i);
  726. size_type j = dist(engine);
  727. buf = view(de, j);
  728. view(de, j) = view(de, i);
  729. view(de, i) = buf;
  730. }
  731. }
  732. }
  733. /**
  734. * Randomly permute a sequence, or return a permuted range.
  735. *
  736. * If the first parameter is an integer, this function creates a new
  737. * ``arange(e)`` and returns it randomly permuted. Otherwise, this
  738. * function creates a copy of the input, passes it to @sa shuffle and
  739. * returns the result.
  740. *
  741. * @param e input xexpression or integer
  742. * @param engine random number engine to use (optional)
  743. *
  744. * @return randomly permuted copy of container or arange.
  745. */
  746. template <class T, class E>
  747. std::enable_if_t<xtl::is_integral<T>::value, xtensor<T, 1>> permutation(T e, E& engine)
  748. {
  749. xt::xtensor<T, 1> res = xt::arange<T>(e);
  750. shuffle(res, engine);
  751. return res;
  752. }
  753. /// @cond DOXYGEN_INCLUDE_SFINAE
  754. template <class T, class E>
  755. std::enable_if_t<is_xexpression<std::decay_t<T>>::value, std::decay_t<T>> permutation(T&& e, E& engine)
  756. {
  757. using copy_type = std::decay_t<T>;
  758. copy_type res = e;
  759. shuffle(res, engine);
  760. return res;
  761. }
  762. /// @endcond
  763. /**
  764. * Randomly select n unique elements from xexpression e.
  765. * Note: this function makes a copy of your data, and only 1D data is accepted.
  766. *
  767. * @param e expression to sample from
  768. * @param n number of elements to sample
  769. * @param replace whether to sample with or without replacement
  770. * @param engine random number engine
  771. *
  772. * @return xtensor containing 1D container of sampled elements
  773. */
  774. template <class T, class E>
  775. xtensor<typename T::value_type, 1>
  776. choice(const xexpression<T>& e, std::size_t n, bool replace, E& engine)
  777. {
  778. const auto& de = e.derived_cast();
  779. XTENSOR_ASSERT((de.dimension() == 1));
  780. XTENSOR_ASSERT((replace || n <= de.size()));
  781. using result_type = xtensor<typename T::value_type, 1>;
  782. using size_type = typename result_type::size_type;
  783. result_type result;
  784. result.resize({n});
  785. if (replace)
  786. {
  787. auto dist = std::uniform_int_distribution<size_type>(0, de.size() - 1);
  788. for (size_type i = 0; i < n; ++i)
  789. {
  790. result[i] = de.storage()[dist(engine)];
  791. }
  792. }
  793. else
  794. {
  795. // Naive resevoir sampling without weighting:
  796. std::copy(de.storage().begin(), de.storage().begin() + n, result.begin());
  797. size_type i = n;
  798. for (auto it = de.storage().begin() + n; it != de.storage().end(); ++it, ++i)
  799. {
  800. auto idx = std::uniform_int_distribution<size_type>(0, i)(engine);
  801. if (idx < n)
  802. {
  803. result.storage()[idx] = *it;
  804. }
  805. }
  806. }
  807. return result;
  808. }
  809. /**
  810. * Weighted random sampling.
  811. *
  812. * Randomly sample n unique elements from xexpression ``e`` using the discrete distribution
  813. * parametrized by the weights ``w``. When sampling with replacement, this means that the probability
  814. * to sample element ``e[i]`` is defined as
  815. * ``w[i] / sum(w)``.
  816. * Without replacement, this only describes the probability of the first sample element.
  817. * In successive samples, the weight of items already sampled is assumed to be zero.
  818. *
  819. * For weighted random sampling with replacement, binary search with cumulative weights alogrithm is
  820. * used. For weighted random sampling without replacement, the algorithm used is the exponential sort
  821. * from [Efraimidis and Spirakis](https://doi.org/10.1016/j.ipl.2005.11.003) (2006) with the ``weight
  822. * / randexp(1)`` [trick](https://web.archive.org/web/20201021162211/https://krlmlr.github.io/wrswoR/)
  823. * from Kirill Müller.
  824. *
  825. * Note: this function makes a copy of your data, and only 1D data is accepted.
  826. *
  827. * @param e expression to sample from
  828. * @param n number of elements to sample
  829. * @param w expression for the weight distribution.
  830. * Weights must be positive and real-valued but need not sum to 1.
  831. * @param replace set true to sample with replacement
  832. * @param engine random number engine
  833. *
  834. * @return xtensor containing 1D container of sampled elements
  835. */
  836. template <class T, class W, class E>
  837. xtensor<typename T::value_type, 1>
  838. choice(const xexpression<T>& e, std::size_t n, const xexpression<W>& weights, bool replace, E& engine)
  839. {
  840. const auto& de = e.derived_cast();
  841. const auto& dweights = weights.derived_cast();
  842. XTENSOR_ASSERT((de.dimension() == 1));
  843. XTENSOR_ASSERT((replace || n <= de.size()));
  844. XTENSOR_ASSERT((de.size() == dweights.size()));
  845. XTENSOR_ASSERT((de.dimension() == dweights.dimension()));
  846. XTENSOR_ASSERT(xt::all(dweights >= 0));
  847. static_assert(
  848. std::is_floating_point<typename W::value_type>::value,
  849. "Weight expression must be of floating point type"
  850. );
  851. using result_type = xtensor<typename T::value_type, 1>;
  852. using size_type = typename result_type::size_type;
  853. using weight_type = typename W::value_type;
  854. result_type result;
  855. result.resize({n});
  856. if (replace)
  857. {
  858. // Sample u uniformly in the range [0, sum(weights)[
  859. // The index idx of the sampled element is such that weight_cumul[idx - 1] <= u <
  860. // weight_cumul[idx]. Where weight_cumul[-1] is implicitly 0, as the empty sum.
  861. const auto wc = eval(cumsum(dweights));
  862. std::uniform_real_distribution<weight_type> weight_dist{0, wc[wc.size() - 1]};
  863. for (auto& x : result)
  864. {
  865. const auto u = weight_dist(engine);
  866. const auto idx = static_cast<size_type>(
  867. std::upper_bound(wc.cbegin(), wc.cend(), u) - wc.cbegin()
  868. );
  869. x = de[idx];
  870. }
  871. }
  872. else
  873. {
  874. // Compute (modified) keys as weight/randexp(1).
  875. xtensor<weight_type, 1> keys;
  876. keys.resize({dweights.size()});
  877. std::exponential_distribution<weight_type> randexp{weight_type(1)};
  878. std::transform(
  879. dweights.cbegin(),
  880. dweights.cend(),
  881. keys.begin(),
  882. [&randexp, &engine](auto w)
  883. {
  884. return w / randexp(engine);
  885. }
  886. );
  887. // Find indexes for the n biggest key
  888. xtensor<size_type, 1> indices = arange<size_type>(0, dweights.size());
  889. std::partial_sort(
  890. indices.begin(),
  891. indices.begin() + n,
  892. indices.end(),
  893. [&keys](auto i, auto j)
  894. {
  895. return keys[i] > keys[j];
  896. }
  897. );
  898. // Return samples with the n biggest keys
  899. result = index_view(de, xtl::span<size_type>{indices.data(), n});
  900. }
  901. return result;
  902. }
  903. }
  904. }
  905. #endif