Entropy.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #pragma once
  8. #include <algorithm>
  9. #include <random>
  10. namespace facebook {
  11. namespace react {
  12. /*
  13. * The source of pseudo-random numbers and some problem-oriented tools built on
  14. * top of that. We need this class to maintain a reproducible stream of random
  15. * numbers and abstract away complex math of and C++ STL API behind that.
  16. */
  17. class Entropy final {
  18. public:
  19. using Generator = std::mt19937;
  20. /*
  21. * Creates an instance seeded with a real, not pseudo-random, number.
  22. */
  23. Entropy() {
  24. std::random_device device;
  25. seed_ = device();
  26. generator_ = std::mt19937(seed_);
  27. }
  28. /*
  29. * Creates an instance seeded with a given number.
  30. */
  31. Entropy(uint_fast32_t seed) {
  32. seed_ = seed;
  33. generator_ = std::mt19937(seed_);
  34. }
  35. uint_fast32_t getSeed() const {
  36. return seed_;
  37. }
  38. /*
  39. * Family of methods that return uniformly distributed instances of a type
  40. * within a specified range.
  41. */
  42. template <typename T>
  43. bool random() const {
  44. T result;
  45. generateRandomValue(generator_, result);
  46. return result;
  47. }
  48. template <typename T, typename Arg1>
  49. T random(Arg1 arg1) const {
  50. T result;
  51. generateRandomValue(generator_, result, arg1);
  52. return result;
  53. }
  54. template <typename T, typename Arg1, typename Arg2>
  55. T random(Arg1 arg1, Arg2 arg2) const {
  56. T result;
  57. generateRandomValue(generator_, result, arg1, arg2);
  58. return result;
  59. }
  60. void generateRandomValue(
  61. Generator &generator,
  62. bool &result,
  63. double ratio = 0.5) const {
  64. result = generator() % 10000 < 10000 * ratio;
  65. }
  66. void generateRandomValue(Generator &generator, int &result, int min, int max)
  67. const {
  68. std::uniform_int_distribution<int> distribution(min, max);
  69. result = distribution(generator);
  70. }
  71. /*
  72. * Shuffles `std::vector` in place.
  73. */
  74. template <typename T>
  75. void shuffle(T array) const {
  76. std::shuffle(array.begin(), array.end(), generator_);
  77. }
  78. /*
  79. * Distribute items from a given array into buckets using a normal
  80. * distribution and given `deviation`.
  81. */
  82. template <typename T>
  83. std::vector<std::vector<T>> distribute(std::vector<T> items, double deviation)
  84. const {
  85. std::normal_distribution<> distribution{0, deviation};
  86. auto deviationLimit = int(deviation * 10);
  87. auto spreadResult = std::vector<std::vector<T>>(deviationLimit * 2);
  88. std::fill(spreadResult.begin(), spreadResult.end(), std::vector<T>{});
  89. for (auto const &item : items) {
  90. auto position = int(distribution(generator_) + deviationLimit);
  91. position = std::max(0, std::min(position, deviationLimit * 2));
  92. if (position < spreadResult.size()) {
  93. spreadResult[position].push_back(item);
  94. }
  95. }
  96. auto result = std::vector<std::vector<T>>{};
  97. for (auto const &chunk : spreadResult) {
  98. if (chunk.size() == 0) {
  99. continue;
  100. }
  101. result.push_back(chunk);
  102. }
  103. return result;
  104. }
  105. private:
  106. mutable std::mt19937 generator_;
  107. uint_fast32_t seed_;
  108. };
  109. } // namespace react
  110. } // namespace facebook