random_test.cc (10613B)
1 // Unless required by applicable law or agreed to in writing, software 2 // distributed under the License is distributed on an "AS IS" BASIS, 3 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 4 // See the License for the specific language governing permissions and 5 // limitations under the License. 6 7 #include <cstdint> 8 #include <cstdio> 9 #include <ctime> 10 #include <iostream> // cerr 11 #include <random> 12 #include <vector> 13 14 // clang-format off 15 #undef HWY_TARGET_INCLUDE 16 #define HWY_TARGET_INCLUDE "hwy/contrib/random/random_test.cc" // NOLINT 17 #include "hwy/foreach_target.h" // IWYU pragma: keep 18 #include "hwy/highway.h" 19 #include "hwy/contrib/random/random-inl.h" 20 #include "hwy/tests/test_util-inl.h" 21 // clang-format on 22 23 HWY_BEFORE_NAMESPACE(); 24 namespace hwy { 25 namespace HWY_NAMESPACE { // required: unique per target 26 namespace { 27 28 constexpr std::uint64_t tests = 1UL << 10; 29 30 std::uint64_t GetSeed() { return static_cast<uint64_t>(std::time(nullptr)); } 31 32 void RngLoop(const std::uint64_t seed, std::uint64_t* HWY_RESTRICT result, 33 const size_t size) { 34 const ScalableTag<std::uint64_t> d; 35 VectorXoshiro generator{seed}; 36 for (size_t i = 0; i < size; i += Lanes(d)) { 37 Store(generator(), d, result + i); 38 } 39 } 40 41 #if HWY_HAVE_FLOAT64 42 void UniformLoop(const std::uint64_t seed, double* HWY_RESTRICT result, 43 const size_t size) { 44 const ScalableTag<double> d; 45 VectorXoshiro generator{seed}; 46 for (size_t i = 0; i < size; i += Lanes(d)) { 47 Store(generator.Uniform(), d, result + i); 48 } 49 } 50 #endif 51 52 void TestSeeding() { 53 const std::uint64_t seed = GetSeed(); 54 VectorXoshiro generator{seed}; 55 internal::Xoshiro reference{seed}; 56 const auto& state = generator.GetState(); 57 const ScalableTag<std::uint64_t> d; 58 const std::size_t lanes = Lanes(d); 59 for (std::size_t i = 0UL; i < lanes; ++i) { 60 const auto& reference_state = reference.GetState(); 61 for (std::size_t j = 0UL; j < reference_state.size(); ++j) { 62 if (state[{j}][i] != reference_state[j]) { 63 std::cerr << "SEED: " << seed << "\n"; 64 std::cerr << "TEST SEEDING ERROR: "; 65 std::cerr << "state[" << j << "][" << i << "] -> " << state[{j}][i] 66 << " != " << reference_state[j] << "\n"; 67 HWY_ASSERT(0); 68 } 69 } 70 reference.Jump(); 71 } 72 } 73 74 void TestMultiThreadSeeding() { 75 const std::uint64_t seed = GetSeed(); 76 const std::uint64_t threadId = std::random_device()() % 1000; 77 VectorXoshiro generator{seed, threadId}; 78 internal::Xoshiro reference{seed}; 79 80 for (std::size_t i = 0UL; i < threadId; ++i) { 81 reference.LongJump(); 82 } 83 84 const auto& state = generator.GetState(); 85 const ScalableTag<std::uint64_t> d; 86 const std::size_t lanes = Lanes(d); 87 for (std::size_t i = 0UL; i < lanes; ++i) { 88 const auto& reference_state = reference.GetState(); 89 for (std::size_t j = 0UL; j < reference_state.size(); ++j) { 90 if (state[{j}][i] != reference_state[j]) { 91 std::cerr << "SEED: " << seed << std::endl; 92 std::cerr << "TEST SEEDING ERROR: "; 93 std::cerr << "state[" << j << "][" << i << "] -> " << state[{j}][i] 94 << " != " << reference_state[j] << "\n"; 95 HWY_ASSERT(0); 96 } 97 } 98 reference.Jump(); 99 } 100 } 101 102 void TestRandomUint64() { 103 const std::uint64_t seed = GetSeed(); 104 const auto result_array = hwy::MakeUniqueAlignedArray<std::uint64_t>(tests); 105 RngLoop(seed, result_array.get(), tests); 106 std::vector<internal::Xoshiro> reference; 107 reference.emplace_back(seed); 108 const ScalableTag<std::uint64_t> d; 109 const std::size_t lanes = Lanes(d); 110 for (std::size_t i = 1UL; i < lanes; ++i) { 111 auto rng = reference.back(); 112 rng.Jump(); 113 reference.emplace_back(rng); 114 } 115 116 for (std::size_t i = 0UL; i < tests; i += lanes) { 117 for (std::size_t lane = 0UL; lane < lanes; ++lane) { 118 const std::uint64_t result = reference[lane](); 119 if (result_array[i + lane] != result) { 120 std::cerr << "SEED: " << seed << std::endl; 121 std::cerr << "TEST UINT64 GENERATOR ERROR: result_array[" << i + lane 122 << "] -> " << result_array[i + lane] << " != " << result 123 << std::endl; 124 HWY_ASSERT(0); 125 } 126 } 127 } 128 } 129 void TestUniformDist() { 130 #if HWY_HAVE_FLOAT64 131 const std::uint64_t seed = GetSeed(); 132 const auto result_array = hwy::MakeUniqueAlignedArray<double>(tests); 133 UniformLoop(seed, result_array.get(), tests); 134 internal::Xoshiro reference{seed}; 135 const ScalableTag<double> d; 136 const std::size_t lanes = Lanes(d); 137 for (std::size_t i = 0UL; i < tests; i += lanes) { 138 const double result = reference.Uniform(); 139 if (result_array[i] != result) { 140 std::cerr << "SEED: " << seed << std::endl; 141 std::cerr << "TEST UNIFORM GENERATOR ERROR: result_array[" << i << "] -> " 142 << result_array[i] << " != " << result << std::endl; 143 HWY_ASSERT(0); 144 } 145 } 146 #endif // HWY_HAVE_FLOAT64 147 } 148 149 void TestNextNRandomUint64() { 150 const std::uint64_t seed = GetSeed(); 151 VectorXoshiro generator{seed}; 152 const auto result_array = generator.operator()(tests); 153 std::vector<internal::Xoshiro> reference; 154 reference.emplace_back(seed); 155 const ScalableTag<std::uint64_t> d; 156 const std::size_t lanes = Lanes(d); 157 for (std::size_t i = 1UL; i < lanes; ++i) { 158 auto rng = reference.back(); 159 rng.Jump(); 160 reference.emplace_back(rng); 161 } 162 163 for (std::size_t i = 0UL; i < tests; i += lanes) { 164 for (std::size_t lane = 0UL; lane < lanes; ++lane) { 165 const std::uint64_t result = reference[lane](); 166 if (result_array[i + lane] != result) { 167 std::cerr << "SEED: " << seed << std::endl; 168 std::cerr << "TEST UINT64 GENERATOR ERROR: result_array[" << i + lane 169 << "] -> " << result_array[i + lane] << " != " << result 170 << std::endl; 171 HWY_ASSERT(0); 172 } 173 } 174 } 175 } 176 177 void TestNextFixedNRandomUint64() { 178 const std::uint64_t seed = GetSeed(); 179 VectorXoshiro generator{seed}; 180 const auto result_array = generator.operator()<tests>(); 181 std::vector<internal::Xoshiro> reference; 182 reference.emplace_back(seed); 183 const ScalableTag<std::uint64_t> d; 184 const std::size_t lanes = Lanes(d); 185 for (std::size_t i = 1UL; i < lanes; ++i) { 186 auto rng = reference.back(); 187 rng.Jump(); 188 reference.emplace_back(rng); 189 } 190 191 for (std::size_t i = 0UL; i < tests; i += lanes) { 192 for (std::size_t lane = 0UL; lane < lanes; ++lane) { 193 const std::uint64_t result = reference[lane](); 194 if (result_array[i + lane] != result) { 195 std::cerr << "SEED: " << seed << std::endl; 196 std::cerr << "TEST UINT64 GENERATOR ERROR: result_array[" << i + lane 197 << "] -> " << result_array[i + lane] << " != " << result 198 << std::endl; 199 200 HWY_ASSERT(0); 201 } 202 } 203 } 204 } 205 void TestNextNUniformDist() { 206 #if HWY_HAVE_FLOAT64 207 const std::uint64_t seed = GetSeed(); 208 VectorXoshiro generator{seed}; 209 const auto result_array = generator.Uniform(tests); 210 internal::Xoshiro reference{seed}; 211 const ScalableTag<double> d; 212 const std::size_t lanes = Lanes(d); 213 for (std::size_t i = 0UL; i < tests; i += lanes) { 214 const double result = reference.Uniform(); 215 if (result_array[i] != result) { 216 std::cerr << "SEED: " << seed << std::endl; 217 std::cerr << "TEST UNIFORM GENERATOR ERROR: result_array[" << i << "] -> " 218 << result_array[i] << " != " << result << std::endl; 219 220 HWY_ASSERT(0); 221 } 222 } 223 #endif // HWY_HAVE_FLOAT64 224 } 225 226 void TestNextFixedNUniformDist() { 227 #if HWY_HAVE_FLOAT64 228 const std::uint64_t seed = GetSeed(); 229 VectorXoshiro generator{seed}; 230 const auto result_array = generator.Uniform<tests>(); 231 internal::Xoshiro reference{seed}; 232 const ScalableTag<double> d; 233 const std::size_t lanes = Lanes(d); 234 for (std::size_t i = 0UL; i < tests; i += lanes) { 235 const double result = reference.Uniform(); 236 if (result_array[i] != result) { 237 std::cerr << "SEED: " << seed << std::endl; 238 std::cerr << "TEST UNIFORM GENERATOR ERROR: result_array[" << i << "] -> " 239 << result_array[i] << " != " << result << std::endl; 240 HWY_ASSERT(0); 241 } 242 } 243 #endif // HWY_HAVE_FLOAT64 244 } 245 246 void TestCachedXorshiro() { 247 const std::uint64_t seed = GetSeed(); 248 249 CachedXoshiro<> generator{seed}; 250 std::vector<internal::Xoshiro> reference; 251 reference.emplace_back(seed); 252 const ScalableTag<std::uint64_t> d; 253 const std::size_t lanes = Lanes(d); 254 for (std::size_t i = 1UL; i < lanes; ++i) { 255 auto rng = reference.back(); 256 rng.Jump(); 257 reference.emplace_back(rng); 258 } 259 260 for (std::size_t i = 0UL; i < tests; i += lanes) { 261 for (std::size_t lane = 0UL; lane < lanes; ++lane) { 262 const std::uint64_t result = reference[lane](); 263 const std::uint64_t got = generator(); 264 if (got != result) { 265 std::cerr << "SEED: " << seed << std::endl; 266 std::cerr << "TEST CachedXoshiro GENERATOR ERROR: result_array[" 267 << i + lane << "] -> " << got << " != " << result 268 << std::endl; 269 270 HWY_ASSERT(0); 271 } 272 } 273 } 274 } 275 void TestUniformCachedXorshiro() { 276 #if HWY_HAVE_FLOAT64 277 const std::uint64_t seed = GetSeed(); 278 279 CachedXoshiro<> generator{seed}; 280 std::uniform_real_distribution<double> distribution{0., 1.}; 281 for (std::size_t i = 0UL; i < tests; ++i) { 282 const double result = distribution(generator); 283 284 if (result < 0. || result >= 1.) { 285 std::cerr << "SEED: " << seed << std::endl; 286 std::cerr << "TEST CachedXoshiro GENERATOR ERROR: result_array[" << i 287 << "] -> " << result << " not in interval [0, 1)" << std::endl; 288 HWY_ASSERT(0); 289 } 290 } 291 #endif // HWY_HAVE_FLOAT64 292 } 293 294 } // namespace 295 // NOLINTNEXTLINE(google-readability-namespace-comments) 296 } // namespace HWY_NAMESPACE 297 } // namespace hwy 298 HWY_AFTER_NAMESPACE(); // required if not using HWY_ATTR 299 300 #if HWY_ONCE 301 namespace hwy { 302 namespace { 303 HWY_BEFORE_TEST(HwyRandomTest); 304 HWY_EXPORT_AND_TEST_P(HwyRandomTest, TestSeeding); 305 HWY_EXPORT_AND_TEST_P(HwyRandomTest, TestMultiThreadSeeding); 306 HWY_EXPORT_AND_TEST_P(HwyRandomTest, TestRandomUint64); 307 HWY_EXPORT_AND_TEST_P(HwyRandomTest, TestNextNRandomUint64); 308 HWY_EXPORT_AND_TEST_P(HwyRandomTest, TestNextFixedNRandomUint64); 309 HWY_EXPORT_AND_TEST_P(HwyRandomTest, TestCachedXorshiro); 310 HWY_EXPORT_AND_TEST_P(HwyRandomTest, TestUniformDist); 311 HWY_EXPORT_AND_TEST_P(HwyRandomTest, TestNextNUniformDist); 312 HWY_EXPORT_AND_TEST_P(HwyRandomTest, TestNextFixedNUniformDist); 313 HWY_EXPORT_AND_TEST_P(HwyRandomTest, TestUniformCachedXorshiro); 314 HWY_AFTER_TEST(); 315 } // namespace 316 } // namespace hwy 317 HWY_TEST_MAIN(); 318 #endif // HWY_ONCE