random.h 2.9 KB
Newer Older
1
2
3
4
/*!
 * Copyright (c) 2016 Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See LICENSE file in the project root for license information.
 */
5
6
#ifndef LIGHTGBM_INCLUDE_LIGHTGBM_UTILS_RANDOM_H_
#define LIGHTGBM_INCLUDE_LIGHTGBM_UTILS_RANDOM_H_
Guolin Ke's avatar
Guolin Ke committed
7
8
9

#include <cstdint>
#include <random>
Guolin Ke's avatar
Guolin Ke committed
10
#include <set>
11
#include <vector>
Guolin Ke's avatar
Guolin Ke committed
12
13
14
15
16
17
18

namespace LightGBM {

/*!
* \brief A wrapper for random generator
*/
class Random {
Nikita Titov's avatar
Nikita Titov committed
19
 public:
Guolin Ke's avatar
Guolin Ke committed
20
21
22
  /*!
  * \brief Constructor, with random seed
  */
Guolin Ke's avatar
Guolin Ke committed
23
  Random() {
Guolin Ke's avatar
Guolin Ke committed
24
    std::random_device rd;
25
    auto generator = std::mt19937(rd());
Guolin Ke's avatar
Guolin Ke committed
26
    std::uniform_int_distribution<int> distribution(0, x);
27
    x = distribution(generator);
Guolin Ke's avatar
Guolin Ke committed
28
29
30
31
  }
  /*!
  * \brief Constructor, with specific seed
  */
Guolin Ke's avatar
Guolin Ke committed
32
  explicit Random(int seed) {
Guolin Ke's avatar
Guolin Ke committed
33
    x = seed;
Guolin Ke's avatar
Guolin Ke committed
34
35
  }
  /*!
Guolin Ke's avatar
Guolin Ke committed
36
37
38
39
40
41
42
43
44
45
46
  * \brief Generate random integer, int16 range. [0, 65536]
  * \param lower_bound lower bound
  * \param upper_bound upper bound
  * \return The random integer between [lower_bound, upper_bound)
  */
  inline int NextShort(int lower_bound, int upper_bound) {
    return (RandInt16()) % (upper_bound - lower_bound) + lower_bound;
  }

  /*!
  * \brief Generate random integer, int32 range
Guolin Ke's avatar
Guolin Ke committed
47
48
49
50
  * \param lower_bound lower bound
  * \param upper_bound upper bound
  * \return The random integer between [lower_bound, upper_bound)
  */
Guolin Ke's avatar
Guolin Ke committed
51
  inline int NextInt(int lower_bound, int upper_bound) {
Guolin Ke's avatar
Guolin Ke committed
52
    return (RandInt32()) % (upper_bound - lower_bound) + lower_bound;
Guolin Ke's avatar
Guolin Ke committed
53
  }
Guolin Ke's avatar
Guolin Ke committed
54

Guolin Ke's avatar
Guolin Ke committed
55
56
57
58
  /*!
  * \brief Generate random float data
  * \return The random float between [0.0, 1.0)
  */
Guolin Ke's avatar
Guolin Ke committed
59
  inline float NextFloat() {
Guolin Ke's avatar
Guolin Ke committed
60
    // get random float in [0,1)
Guolin Ke's avatar
Guolin Ke committed
61
    return static_cast<float>(RandInt16()) / (32768.0f);
Guolin Ke's avatar
Guolin Ke committed
62
63
64
65
66
67
68
  }
  /*!
  * \brief Sample K data from {0,1,...,N-1}
  * \param N
  * \param K
  * \return K Ordered sampled data from {0,1,...,N-1}
  */
69
70
  inline std::vector<int> Sample(int N, int K) {
    std::vector<int> ret;
71
    ret.reserve(K);
Guolin Ke's avatar
Guolin Ke committed
72
    if (K > N || K <= 0) {
Guolin Ke's avatar
Guolin Ke committed
73
      return ret;
74
75
    } else if (K == N) {
      for (int i = 0; i < N; ++i) {
Guolin Ke's avatar
Guolin Ke committed
76
77
        ret.push_back(i);
      }
Guolin Ke's avatar
Guolin Ke committed
78
    } else if (K > 1 && K > (N / std::log2(K))) {
79
80
81
82
83
84
85
      for (int i = 0; i < N; ++i) {
        double prob = (K - ret.size()) / static_cast<double>(N - i);
        if (NextFloat() < prob) {
          ret.push_back(i);
        }
      }
    } else {
Guolin Ke's avatar
Guolin Ke committed
86
      std::set<int> sample_set;
Guolin Ke's avatar
Guolin Ke committed
87
      for (int r = N - K; r < N; ++r) {
88
        int v = NextInt(0, r + 1);
Guolin Ke's avatar
Guolin Ke committed
89
90
        if (!sample_set.insert(v).second) {
          sample_set.insert(r);
Guolin Ke's avatar
Guolin Ke committed
91
92
93
94
        }
      }
      for (auto iter = sample_set.begin(); iter != sample_set.end(); ++iter) {
        ret.push_back(*iter);
95
      }
Guolin Ke's avatar
Guolin Ke committed
96
97
98
    }
    return ret;
  }
99

Nikita Titov's avatar
Nikita Titov committed
100
 private:
Guolin Ke's avatar
Guolin Ke committed
101
  inline int RandInt16() {
Guolin Ke's avatar
Guolin Ke committed
102
    x = (214013 * x + 2531011);
Guolin Ke's avatar
Guolin Ke committed
103
    return static_cast<int>((x >> 16) & 0x7FFF);
Guolin Ke's avatar
Guolin Ke committed
104
  }
Guolin Ke's avatar
Guolin Ke committed
105
106
107

  inline int RandInt32() {
    x = (214013 * x + 2531011);
Guolin Ke's avatar
Guolin Ke committed
108
    return static_cast<int>(x & 0x7FFFFFFF);
Guolin Ke's avatar
Guolin Ke committed
109
110
  }

111
  unsigned int x = 123456789;
Guolin Ke's avatar
Guolin Ke committed
112
113
};

Guolin Ke's avatar
Guolin Ke committed
114

Guolin Ke's avatar
Guolin Ke committed
115
116
}  // namespace LightGBM

117
#endif   // LIGHTGBM_INCLUDE_LIGHTGBM_UTILS_RANDOM_H_