| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007 |
- /***************************************************************************
- * 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. *
- ****************************************************************************/
- /**
- * @brief functions to obtain xgenerators generating random numbers with given shape
- */
- #ifndef XTENSOR_RANDOM_HPP
- #define XTENSOR_RANDOM_HPP
- #include <algorithm>
- #include <functional>
- #include <random>
- #include <type_traits>
- #include <utility>
- #include <xtl/xspan.hpp>
- #include "xbuilder.hpp"
- #include "xgenerator.hpp"
- #include "xindex_view.hpp"
- #include "xmath.hpp"
- #include "xtensor.hpp"
- #include "xtensor_config.hpp"
- #include "xview.hpp"
- namespace xt
- {
- /*********************
- * Random generators *
- *********************/
- namespace random
- {
- using default_engine_type = std::mt19937;
- using seed_type = default_engine_type::result_type;
- default_engine_type& get_default_random_engine();
- void seed(seed_type seed);
- template <class T, class S, class E = random::default_engine_type>
- auto rand(const S& shape, T lower = 0, T upper = 1, E& engine = random::get_default_random_engine());
- template <class T, class S, class E = random::default_engine_type>
- auto randint(
- const S& shape,
- T lower = 0,
- T upper = (std::numeric_limits<T>::max)(),
- E& engine = random::get_default_random_engine()
- );
- template <class T, class S, class E = random::default_engine_type>
- auto randn(const S& shape, T mean = 0, T std_dev = 1, E& engine = random::get_default_random_engine());
- template <class T, class S, class D = double, class E = random::default_engine_type>
- auto
- binomial(const S& shape, T trials = 1, D prob = 0.5, E& engine = random::get_default_random_engine());
- template <class T, class S, class D = double, class E = random::default_engine_type>
- auto geometric(const S& shape, D prob = 0.5, E& engine = random::get_default_random_engine());
- template <class T, class S, class D = double, class E = random::default_engine_type>
- auto
- negative_binomial(const S& shape, T k = 1, D prob = 0.5, E& engine = random::get_default_random_engine());
- template <class T, class S, class D = double, class E = random::default_engine_type>
- auto poisson(const S& shape, D rate = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class S, class E = random::default_engine_type>
- auto exponential(const S& shape, T rate = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class S, class E = random::default_engine_type>
- auto
- gamma(const S& shape, T alpha = 1.0, T beta = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class S, class E = random::default_engine_type>
- auto weibull(const S& shape, T a = 1.0, T b = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class S, class E = random::default_engine_type>
- auto
- extreme_value(const S& shape, T a = 0.0, T b = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class S, class E = random::default_engine_type>
- auto
- lognormal(const S& shape, T mean = 0, T std_dev = 1, E& engine = random::get_default_random_engine());
- template <class T, class S, class E = random::default_engine_type>
- auto chi_squared(const S& shape, T deg = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class S, class E = random::default_engine_type>
- auto cauchy(const S& shape, T a = 0.0, T b = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class S, class E = random::default_engine_type>
- auto fisher_f(const S& shape, T m = 1.0, T n = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class S, class E = random::default_engine_type>
- auto student_t(const S& shape, T n = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class I, std::size_t L, class E = random::default_engine_type>
- auto
- rand(const I (&shape)[L], T lower = 0, T upper = 1, E& engine = random::get_default_random_engine());
- template <class T, class I, std::size_t L, class E = random::default_engine_type>
- auto randint(
- const I (&shape)[L],
- T lower = 0,
- T upper = (std::numeric_limits<T>::max)(),
- E& engine = random::get_default_random_engine()
- );
- template <class T, class I, std::size_t L, class E = random::default_engine_type>
- auto
- randn(const I (&shape)[L], T mean = 0, T std_dev = 1, E& engine = random::get_default_random_engine());
- template <class T, class I, std::size_t L, class D = double, class E = random::default_engine_type>
- auto
- binomial(const I (&shape)[L], T trials = 1, D prob = 0.5, E& engine = random::get_default_random_engine());
- template <class T, class I, std::size_t L, class D = double, class E = random::default_engine_type>
- auto geometric(const I (&shape)[L], D prob = 0.5, E& engine = random::get_default_random_engine());
- template <class T, class I, std::size_t L, class D = double, class E = random::default_engine_type>
- auto negative_binomial(
- const I (&shape)[L],
- T k = 1,
- D prob = 0.5,
- E& engine = random::get_default_random_engine()
- );
- template <class T, class I, std::size_t L, class D = double, class E = random::default_engine_type>
- auto poisson(const I (&shape)[L], D rate = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class I, std::size_t L, class E = random::default_engine_type>
- auto exponential(const I (&shape)[L], T rate = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class I, std::size_t L, class E = random::default_engine_type>
- auto
- gamma(const I (&shape)[L], T alpha = 1.0, T beta = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class I, std::size_t L, class E = random::default_engine_type>
- auto
- weibull(const I (&shape)[L], T a = 1.0, T b = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class I, std::size_t L, class E = random::default_engine_type>
- auto
- extreme_value(const I (&shape)[L], T a = 0.0, T b = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class I, std::size_t L, class E = random::default_engine_type>
- auto lognormal(
- const I (&shape)[L],
- T mean = 0.0,
- T std_dev = 1.0,
- E& engine = random::get_default_random_engine()
- );
- template <class T, class I, std::size_t L, class E = random::default_engine_type>
- auto chi_squared(const I (&shape)[L], T deg = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class I, std::size_t L, class E = random::default_engine_type>
- auto cauchy(const I (&shape)[L], T a = 0.0, T b = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class I, std::size_t L, class E = random::default_engine_type>
- auto
- fisher_f(const I (&shape)[L], T m = 1.0, T n = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class I, std::size_t L, class E = random::default_engine_type>
- auto student_t(const I (&shape)[L], T n = 1.0, E& engine = random::get_default_random_engine());
- template <class T, class E = random::default_engine_type>
- void shuffle(xexpression<T>& e, E& engine = random::get_default_random_engine());
- template <class T, class E = random::default_engine_type>
- std::enable_if_t<xtl::is_integral<T>::value, xtensor<T, 1>>
- permutation(T e, E& engine = random::get_default_random_engine());
- template <class T, class E = random::default_engine_type>
- std::enable_if_t<is_xexpression<std::decay_t<T>>::value, std::decay_t<T>>
- permutation(T&& e, E& engine = random::get_default_random_engine());
- template <class T, class E = random::default_engine_type>
- xtensor<typename T::value_type, 1> choice(
- const xexpression<T>& e,
- std::size_t n,
- bool replace = true,
- E& engine = random::get_default_random_engine()
- );
- template <class T, class W, class E = random::default_engine_type>
- xtensor<typename T::value_type, 1> choice(
- const xexpression<T>& e,
- std::size_t n,
- const xexpression<W>& weights,
- bool replace = true,
- E& engine = random::get_default_random_engine()
- );
- }
- namespace detail
- {
- template <class T, class E, class D>
- struct random_impl
- {
- using value_type = T;
- random_impl(E& engine, D&& dist)
- : m_engine(engine)
- , m_dist(std::move(dist))
- {
- }
- template <class... Args>
- inline value_type operator()(Args...) const
- {
- return m_dist(m_engine);
- }
- template <class It>
- inline value_type element(It, It) const
- {
- return m_dist(m_engine);
- }
- template <class EX>
- inline void assign_to(xexpression<EX>& e) const noexcept
- {
- // Note: we're not going row/col major here
- auto& ed = e.derived_cast();
- for (auto&& el : ed.storage())
- {
- el = m_dist(m_engine);
- }
- }
- private:
- E& m_engine;
- mutable D m_dist;
- };
- }
- namespace random
- {
- /**
- * Returns a reference to the default random number engine
- */
- inline default_engine_type& get_default_random_engine()
- {
- static default_engine_type mt;
- return mt;
- }
- /**
- * Seeds the default random number generator with @p seed
- * @param seed The seed
- */
- inline void seed(seed_type seed)
- {
- get_default_random_engine().seed(seed);
- }
- /**
- * xexpression with specified @p shape containing uniformly distributed random numbers
- * in the interval from @p lower to @p upper, excluding upper.
- *
- * Numbers are drawn from @c std::uniform_real_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param lower lower bound
- * @param upper upper bound
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class E>
- inline auto rand(const S& shape, T lower, T upper, E& engine)
- {
- std::uniform_real_distribution<T> dist(lower, upper);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing uniformly distributed
- * random integers in the interval from @p lower to @p upper, excluding upper.
- *
- * Numbers are drawn from @c std::uniform_int_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param lower lower bound
- * @param upper upper bound
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class E>
- inline auto randint(const S& shape, T lower, T upper, E& engine)
- {
- std::uniform_int_distribution<T> dist(lower, T(upper - 1));
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing numbers sampled from
- * the Normal (Gaussian) random number distribution with mean @p mean and
- * standard deviation @p std_dev.
- *
- * Numbers are drawn from @c std::normal_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param mean mean of normal distribution
- * @param std_dev standard deviation of normal distribution
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class E>
- inline auto randn(const S& shape, T mean, T std_dev, E& engine)
- {
- std::normal_distribution<T> dist(mean, std_dev);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing numbers sampled from
- * the binomial random number distribution for @p trials trials with
- * probability of success equal to @p prob.
- *
- * Numbers are drawn from @c std::binomial_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param trials number of Bernoulli trials
- * @param prob probability of success of each trial
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class D, class E>
- inline auto binomial(const S& shape, T trials, D prob, E& engine)
- {
- std::binomial_distribution<T> dist(trials, prob);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing numbers sampled from
- * a gemoetric random number distribution with
- * probability of success equal to @p prob for each of the Bernoulli trials.
- *
- * Numbers are drawn from @c std::geometric_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param prob probability of success of each trial
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class D, class E>
- inline auto geometric(const S& shape, D prob, E& engine)
- {
- std::geometric_distribution<T> dist(prob);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing numbers sampled from
- * a negative binomial random number distribution (also known as Pascal distribution)
- * that returns the number of successes before @p k trials with probability of success
- * equal to @p prob for each of the Bernoulli trials.
- *
- * Numbers are drawn from @c std::negative_binomial_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param k number of unsuccessful trials
- * @param prob probability of success of each trial
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class D, class E>
- inline auto negative_binomial(const S& shape, T k, D prob, E& engine)
- {
- std::negative_binomial_distribution<T> dist(k, prob);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing numbers sampled from
- * a Poisson random number distribution with rate @p rate
- *
- * Numbers are drawn from @c std::poisson_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param rate rate of Poisson distribution
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class D, class E>
- inline auto poisson(const S& shape, D rate, E& engine)
- {
- std::poisson_distribution<T> dist(rate);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing numbers sampled from
- * a exponential random number distribution with rate @p rate
- *
- * Numbers are drawn from @c std::exponential_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param rate rate of exponential distribution
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class E>
- inline auto exponential(const S& shape, T rate, E& engine)
- {
- std::exponential_distribution<T> dist(rate);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing numbers sampled from
- * a gamma random number distribution with shape @p alpha and scale @p beta
- *
- * Numbers are drawn from @c std::gamma_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param alpha shape of the gamma distribution
- * @param beta scale of the gamma distribution
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class E>
- inline auto gamma(const S& shape, T alpha, T beta, E& engine)
- {
- std::gamma_distribution<T> dist(alpha, beta);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing numbers sampled from
- * a Weibull random number distribution with shape @p a and scale @p b
- *
- * Numbers are drawn from @c std::weibull_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param a shape of the weibull distribution
- * @param b scale of the weibull distribution
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class E>
- inline auto weibull(const S& shape, T a, T b, E& engine)
- {
- std::weibull_distribution<T> dist(a, b);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing numbers sampled from
- * a extreme value random number distribution with shape @p a and scale @p b
- *
- * Numbers are drawn from @c std::extreme_value_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param a shape of the extreme value distribution
- * @param b scale of the extreme value distribution
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class E>
- inline auto extreme_value(const S& shape, T a, T b, E& engine)
- {
- std::extreme_value_distribution<T> dist(a, b);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing numbers sampled from
- * the Log-Normal random number distribution with mean @p mean and
- * standard deviation @p std_dev.
- *
- * Numbers are drawn from @c std::lognormal_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param mean mean of normal distribution
- * @param std_dev standard deviation of normal distribution
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class E>
- inline auto lognormal(const S& shape, T mean, T std_dev, E& engine)
- {
- std::lognormal_distribution<T> dist(mean, std_dev);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing numbers sampled from
- * the chi-squared random number distribution with @p deg degrees of freedom.
- *
- * Numbers are drawn from @c std::chi_squared_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param deg degrees of freedom
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class E>
- inline auto chi_squared(const S& shape, T deg, E& engine)
- {
- std::chi_squared_distribution<T> dist(deg);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing numbers sampled from
- * a Cauchy random number distribution with peak @p a and scale @p b
- *
- * Numbers are drawn from @c std::cauchy_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param a peak of the Cauchy distribution
- * @param b scale of the Cauchy distribution
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class E>
- inline auto cauchy(const S& shape, T a, T b, E& engine)
- {
- std::cauchy_distribution<T> dist(a, b);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing numbers sampled from
- * a Fisher-f random number distribution with numerator degrees of
- * freedom equal to @p m and denominator degrees of freedom equal to @p n
- *
- * Numbers are drawn from @c std::fisher_f_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param m numerator degrees of freedom
- * @param n denominator degrees of freedom
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class E>
- inline auto fisher_f(const S& shape, T m, T n, E& engine)
- {
- std::fisher_f_distribution<T> dist(m, n);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * xexpression with specified @p shape containing numbers sampled from
- * a Student-t random number distribution with degrees of
- * freedom equal to @p n
- *
- * Numbers are drawn from @c std::student_t_distribution.
- *
- * @param shape shape of resulting xexpression
- * @param n degrees of freedom
- * @param engine random number engine
- * @tparam T number type to use
- */
- template <class T, class S, class E>
- inline auto student_t(const S& shape, T n, E& engine)
- {
- std::student_t_distribution<T> dist(n);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class E>
- inline auto rand(const I (&shape)[L], T lower, T upper, E& engine)
- {
- std::uniform_real_distribution<T> dist(lower, upper);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class E>
- inline auto randint(const I (&shape)[L], T lower, T upper, E& engine)
- {
- std::uniform_int_distribution<T> dist(lower, T(upper - 1));
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class E>
- inline auto randn(const I (&shape)[L], T mean, T std_dev, E& engine)
- {
- std::normal_distribution<T> dist(mean, std_dev);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class D, class E>
- inline auto binomial(const I (&shape)[L], T trials, D prob, E& engine)
- {
- std::binomial_distribution<T> dist(trials, prob);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class D, class E>
- inline auto geometric(const I (&shape)[L], D prob, E& engine)
- {
- std::geometric_distribution<T> dist(prob);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class D, class E>
- inline auto negative_binomial(const I (&shape)[L], T k, D prob, E& engine)
- {
- std::negative_binomial_distribution<T> dist(k, prob);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class D, class E>
- inline auto poisson(const I (&shape)[L], D rate, E& engine)
- {
- std::poisson_distribution<T> dist(rate);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class E>
- inline auto exponential(const I (&shape)[L], T rate, E& engine)
- {
- std::exponential_distribution<T> dist(rate);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class E>
- inline auto gamma(const I (&shape)[L], T alpha, T beta, E& engine)
- {
- std::gamma_distribution<T> dist(alpha, beta);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class E>
- inline auto weibull(const I (&shape)[L], T a, T b, E& engine)
- {
- std::weibull_distribution<T> dist(a, b);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class E>
- inline auto extreme_value(const I (&shape)[L], T a, T b, E& engine)
- {
- std::extreme_value_distribution<T> dist(a, b);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class E>
- inline auto lognormal(const I (&shape)[L], T mean, T std_dev, E& engine)
- {
- std::lognormal_distribution<T> dist(mean, std_dev);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class E>
- inline auto chi_squared(const I (&shape)[L], T deg, E& engine)
- {
- std::chi_squared_distribution<T> dist(deg);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class E>
- inline auto cauchy(const I (&shape)[L], T a, T b, E& engine)
- {
- std::cauchy_distribution<T> dist(a, b);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class E>
- inline auto fisher_f(const I (&shape)[L], T m, T n, E& engine)
- {
- std::fisher_f_distribution<T> dist(m, n);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- template <class T, class I, std::size_t L, class E>
- inline auto student_t(const I (&shape)[L], T n, E& engine)
- {
- std::student_t_distribution<T> dist(n);
- return detail::make_xgenerator(
- detail::random_impl<T, E, decltype(dist)>(engine, std::move(dist)),
- shape
- );
- }
- /**
- * Randomly shuffle elements inplace in xcontainer along first axis.
- * The order of sub-arrays is changed but their contents remain the same.
- *
- * @param e xcontainer to shuffle inplace
- * @param engine random number engine
- */
- template <class T, class E>
- void shuffle(xexpression<T>& e, E& engine)
- {
- T& de = e.derived_cast();
- if (de.dimension() == 1)
- {
- using size_type = typename T::size_type;
- auto first = de.begin();
- auto last = de.end();
- for (size_type i = std::size_t((last - first) - 1); i > 0; --i)
- {
- std::uniform_int_distribution<size_type> dist(0, i);
- auto j = dist(engine);
- using std::swap;
- swap(first[i], first[j]);
- }
- }
- else
- {
- using size_type = typename T::size_type;
- decltype(auto) buf = empty_like(view(de, 0));
- for (size_type i = de.shape()[0] - 1; i > 0; --i)
- {
- std::uniform_int_distribution<size_type> dist(0, i);
- size_type j = dist(engine);
- buf = view(de, j);
- view(de, j) = view(de, i);
- view(de, i) = buf;
- }
- }
- }
- /**
- * Randomly permute a sequence, or return a permuted range.
- *
- * If the first parameter is an integer, this function creates a new
- * ``arange(e)`` and returns it randomly permuted. Otherwise, this
- * function creates a copy of the input, passes it to @sa shuffle and
- * returns the result.
- *
- * @param e input xexpression or integer
- * @param engine random number engine to use (optional)
- *
- * @return randomly permuted copy of container or arange.
- */
- template <class T, class E>
- std::enable_if_t<xtl::is_integral<T>::value, xtensor<T, 1>> permutation(T e, E& engine)
- {
- xt::xtensor<T, 1> res = xt::arange<T>(e);
- shuffle(res, engine);
- return res;
- }
- /// @cond DOXYGEN_INCLUDE_SFINAE
- template <class T, class E>
- std::enable_if_t<is_xexpression<std::decay_t<T>>::value, std::decay_t<T>> permutation(T&& e, E& engine)
- {
- using copy_type = std::decay_t<T>;
- copy_type res = e;
- shuffle(res, engine);
- return res;
- }
- /// @endcond
- /**
- * Randomly select n unique elements from xexpression e.
- * Note: this function makes a copy of your data, and only 1D data is accepted.
- *
- * @param e expression to sample from
- * @param n number of elements to sample
- * @param replace whether to sample with or without replacement
- * @param engine random number engine
- *
- * @return xtensor containing 1D container of sampled elements
- */
- template <class T, class E>
- xtensor<typename T::value_type, 1>
- choice(const xexpression<T>& e, std::size_t n, bool replace, E& engine)
- {
- const auto& de = e.derived_cast();
- XTENSOR_ASSERT((de.dimension() == 1));
- XTENSOR_ASSERT((replace || n <= de.size()));
- using result_type = xtensor<typename T::value_type, 1>;
- using size_type = typename result_type::size_type;
- result_type result;
- result.resize({n});
- if (replace)
- {
- auto dist = std::uniform_int_distribution<size_type>(0, de.size() - 1);
- for (size_type i = 0; i < n; ++i)
- {
- result[i] = de.storage()[dist(engine)];
- }
- }
- else
- {
- // Naive resevoir sampling without weighting:
- std::copy(de.storage().begin(), de.storage().begin() + n, result.begin());
- size_type i = n;
- for (auto it = de.storage().begin() + n; it != de.storage().end(); ++it, ++i)
- {
- auto idx = std::uniform_int_distribution<size_type>(0, i)(engine);
- if (idx < n)
- {
- result.storage()[idx] = *it;
- }
- }
- }
- return result;
- }
- /**
- * Weighted random sampling.
- *
- * Randomly sample n unique elements from xexpression ``e`` using the discrete distribution
- * parametrized by the weights ``w``. When sampling with replacement, this means that the probability
- * to sample element ``e[i]`` is defined as
- * ``w[i] / sum(w)``.
- * Without replacement, this only describes the probability of the first sample element.
- * In successive samples, the weight of items already sampled is assumed to be zero.
- *
- * For weighted random sampling with replacement, binary search with cumulative weights alogrithm is
- * used. For weighted random sampling without replacement, the algorithm used is the exponential sort
- * from [Efraimidis and Spirakis](https://doi.org/10.1016/j.ipl.2005.11.003) (2006) with the ``weight
- * / randexp(1)`` [trick](https://web.archive.org/web/20201021162211/https://krlmlr.github.io/wrswoR/)
- * from Kirill Müller.
- *
- * Note: this function makes a copy of your data, and only 1D data is accepted.
- *
- * @param e expression to sample from
- * @param n number of elements to sample
- * @param w expression for the weight distribution.
- * Weights must be positive and real-valued but need not sum to 1.
- * @param replace set true to sample with replacement
- * @param engine random number engine
- *
- * @return xtensor containing 1D container of sampled elements
- */
- template <class T, class W, class E>
- xtensor<typename T::value_type, 1>
- choice(const xexpression<T>& e, std::size_t n, const xexpression<W>& weights, bool replace, E& engine)
- {
- const auto& de = e.derived_cast();
- const auto& dweights = weights.derived_cast();
- XTENSOR_ASSERT((de.dimension() == 1));
- XTENSOR_ASSERT((replace || n <= de.size()));
- XTENSOR_ASSERT((de.size() == dweights.size()));
- XTENSOR_ASSERT((de.dimension() == dweights.dimension()));
- XTENSOR_ASSERT(xt::all(dweights >= 0));
- static_assert(
- std::is_floating_point<typename W::value_type>::value,
- "Weight expression must be of floating point type"
- );
- using result_type = xtensor<typename T::value_type, 1>;
- using size_type = typename result_type::size_type;
- using weight_type = typename W::value_type;
- result_type result;
- result.resize({n});
- if (replace)
- {
- // Sample u uniformly in the range [0, sum(weights)[
- // The index idx of the sampled element is such that weight_cumul[idx - 1] <= u <
- // weight_cumul[idx]. Where weight_cumul[-1] is implicitly 0, as the empty sum.
- const auto wc = eval(cumsum(dweights));
- std::uniform_real_distribution<weight_type> weight_dist{0, wc[wc.size() - 1]};
- for (auto& x : result)
- {
- const auto u = weight_dist(engine);
- const auto idx = static_cast<size_type>(
- std::upper_bound(wc.cbegin(), wc.cend(), u) - wc.cbegin()
- );
- x = de[idx];
- }
- }
- else
- {
- // Compute (modified) keys as weight/randexp(1).
- xtensor<weight_type, 1> keys;
- keys.resize({dweights.size()});
- std::exponential_distribution<weight_type> randexp{weight_type(1)};
- std::transform(
- dweights.cbegin(),
- dweights.cend(),
- keys.begin(),
- [&randexp, &engine](auto w)
- {
- return w / randexp(engine);
- }
- );
- // Find indexes for the n biggest key
- xtensor<size_type, 1> indices = arange<size_type>(0, dweights.size());
- std::partial_sort(
- indices.begin(),
- indices.begin() + n,
- indices.end(),
- [&keys](auto i, auto j)
- {
- return keys[i] > keys[j];
- }
- );
- // Return samples with the n biggest keys
- result = index_view(de, xtl::span<size_type>{indices.data(), n});
- }
- return result;
- }
- }
- }
- #endif
|