Files
wehub-resource-sync 26446540fa
Lint / lint (push) Waiting to run
CI / MacOS (push) Waiting to run
CI / Windows (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:36:25 +08:00

140 lines
5.1 KiB
C++

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*!
* \file random_engine.h
* \brief Random number generator. It provides a generic interface consistent with
* `std::uniform_random_bit_generator`
*/
#ifndef TVM_S_TIR_RANDOM_ENGINE_H_
#define TVM_S_TIR_RANDOM_ENGINE_H_
#include <tvm/ffi/error.h>
#include <cstdint>
#include <random>
namespace tvm {
namespace s_tir {
/*!
* \brief This linear congruential engine is a drop-in replacement for std::minstd_rand. It strictly
* corresponds to std::minstd_rand and is designed to be platform-independent.
* \note Our linear congruential engine is a complete implementation of
* std::uniform_random_bit_generator so it can be used as generator for any STL random number
* distribution. However, parts of std::linear_congruential_engine's member functions are not
* included for simplification. For full member functions of std::minstd_rand, please check out the
* following link: https://en.cppreference.com/w/cpp/numeric/random/linear_congruential_engine
*/
class LinearCongruentialEngine {
public:
using TRandState = int64_t;
/*! \brief The result type. */
using result_type = uint64_t;
/*! \brief The multiplier */
static constexpr TRandState multiplier = 48271;
/*! \brief The increment */
static constexpr TRandState increment = 0;
/*! \brief The modulus */
static constexpr TRandState modulus = 2147483647;
/*! \brief The minimum possible value of random state here. */
static constexpr result_type min() { return 0; }
/*! \brief The maximum possible value of random state here. */
static constexpr result_type max() { return modulus - 1; }
/*!
* \brief Get a device random state
* \return The random state
*/
static TRandState DeviceRandom() {
std::random_device rd;
return rd() % modulus;
}
/*!
* \brief Operator to move the random state to the next and return the new random state. According
* to definition of linear congruential engine, the new random state value is computed as
* new_random_state = (current_random_state * multiplier + increment) % modulus.
* \return The next current random state value in the type of result_type.
* \note In order for better efficiency, the implementation here has a few assumptions:
* 1. The multiplication and addition won't overflow.
* 2. The given random state pointer `rand_state_ptr` is not nullptr.
* 3. The given random state `*(rand_state_ptr)` is in the range of [0, modulus - 1].
*/
result_type operator()() {
(*rand_state_ptr_) = ((*rand_state_ptr_) * multiplier + increment) % modulus;
return *rand_state_ptr_;
}
/*!
* \brief Normalize the random seed to the range of [1, modulus - 1].
* \param rand_state The random seed.
* \return The normalized random seed.
*/
static TRandState NormalizeSeed(TRandState rand_state) {
if (rand_state == -1) {
rand_state = DeviceRandom();
} else {
rand_state %= modulus;
}
if (rand_state == 0) {
rand_state = 1;
}
if (rand_state < 0) {
TVM_FFI_THROW(ValueError) << "Random seed must be non-negative";
}
return rand_state;
}
/*!
* \brief Change the start random state of RNG with the seed of a new random state value.
* \param rand_state The random state given in result_type.
*/
void Seed(TRandState rand_state) {
TVM_FFI_ICHECK(rand_state_ptr_ != nullptr);
*rand_state_ptr_ = NormalizeSeed(rand_state);
}
/*!
* \brief Fork a new seed for another RNG from current random state.
* \return The forked seed.
*/
TRandState ForkSeed() {
// In order for reproducibility, we compute the new seed using RNG's random state and a
// different set of parameters. Note that both 32767 and 1999999973 are prime numbers.
return ((*this)() * 32767) % 1999999973;
}
/*!
* \brief Construct a random number generator with a random state pointer.
* \param rand_state_ptr The random state pointer given in result_type*.
* \note The random state is not checked for whether it's nullptr and whether it's in the range of
* [0, modulus-1]. We assume the given random state is valid or the Seed function would be
* called right after the constructor before any usage.
*/
explicit LinearCongruentialEngine(TRandState* rand_state_ptr) {
rand_state_ptr_ = rand_state_ptr;
}
private:
TRandState* rand_state_ptr_;
};
} // namespace s_tir
} // namespace tvm
#endif // TVM_S_TIR_RANDOM_ENGINE_H_