Skip to content

Commit

Permalink
Implement random manager class (#19)
Browse files Browse the repository at this point in the history
* Implement random manager class

Signed-off-by: jparisu <[email protected]>

* Add test implementation

Signed-off-by: jparisu <[email protected]>

* Add documentation

Signed-off-by: jparisu <[email protected]>

* fix windows issues

Signed-off-by: jparisu <[email protected]>

* apply suggesstions

Signed-off-by: jparisu <[email protected]>

* Add new features and test

Signed-off-by: jparisu <[email protected]>

* Implement TSafe manager

Signed-off-by: jparisu <[email protected]>

* apply suggestions

Signed-off-by: jparisu <[email protected]>

* uncrustify

Signed-off-by: jparisu <[email protected]>

* apply suggestions

Signed-off-by: jparisu <[email protected]>

Signed-off-by: jparisu <[email protected]>
  • Loading branch information
jparisu authored Nov 29, 2022
1 parent 48cf278 commit f97515a
Show file tree
Hide file tree
Showing 16 changed files with 1,300 additions and 11 deletions.
File renamed without changes.
143 changes: 143 additions & 0 deletions cpp_utils/include/cpp_utils/math/random/RandomManager.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed 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 RandomManager.hpp
*
* This file contains class RandomManager definition.
*/

#pragma once

#include <random>

#include <cpp_utils/library/library_dll.h>

namespace eprosima {
namespace utils {

//! Data type of the random numbers generated by class \c RandomManager .
using RandomNumberType = unsigned int;
//! Data type of the seed.
using RandomSeedType = unsigned int;

/**
* @brief Object to manage the generation of random numbers.
*
* This class use different random generators from <random> library to obtain a complete random generator
* with multiple features:
* 1. Generate pure random numbers (no pseudorandom).
* 2. Generate an always equal random sequence from a seed.
* 3. Generate pseudorandom numbers from a specific seed (map each seed with always the same pseudorandom number).
* These 3 features are completely independent and calls between them do not affect each other.
*
* Motivation: Why use this class instead of a std::rand?
* The use of only rand and srand is not recommended by std (https://en.cppreference.com/w/cpp/numeric/random/rand).
* Also the use of rand does not allow to create pure random numbers (it must use srand with a explicit stochastic
* value as time(NULL) (that also can be repeated if executed in same second)) neither to keep state of random
* sequence once a seed has been used. This means that once using rand or srand in any part of the process, the
* random sequence will not be the same.
* Thus, this new class allow to get pure random numbers, get pseudorandom numbers from a seed and creating
* pseudorandom sequences without affecting the normal behaviour of rand and srand.
*
* @note This class it not thread safe.
*/
class RandomManager
{
public:

/**
* @brief Construct a new Random Manager object.
*
* @param original_seed initial seed for sequence number generator.
*/
CPP_UTILS_DllAPI RandomManager(
const RandomSeedType& original_seed = 1);

//! Default destructor
CPP_UTILS_DllAPI ~RandomManager() = default;

/***********************
* NATIVE METHODS
***********************/
/**
* @brief Generate pure random number.
*
* Fulfill 1.
* This method does not affect the sequence generation numbers.
*
* @return Pure random number.
*/
CPP_UTILS_DllAPI RandomNumberType pure_rand () noexcept;

/**
* @brief Get next random number in pseudorandom sequence.
*
* Fulfill 2.
*
* @return Pure random number.
*/
CPP_UTILS_DllAPI RandomNumberType sequence_rand () noexcept;

//! Set seed for the sequence random series.
CPP_UTILS_DllAPI void seed (
const RandomSeedType& seed) noexcept;

/**
* @brief Get a random number related with a seed.
*
* Fulfill 3.
* This method does not affect the sequence generation numbers.
* This always returns the same random number for the same seed.
*
* @param seed to get random number.
*
* @return random number seeded by \c seed .
*/
CPP_UTILS_DllAPI RandomNumberType seeded_rand (
const RandomSeedType& seed) noexcept;


/***********************
* DERIVED METHODS
***********************/
// This methods only extend the API using the common word rand, but they only call native methods.

//! With Pure=true returns \c pure_rand . Otherwise returns \c sequence_rand .
template <bool Pure = false>
RandomNumberType rand () noexcept;

//! Return \c seeded_rand .
CPP_UTILS_DllAPI RandomNumberType rand (
const RandomSeedType& seed) noexcept;

protected:

//! Generation of real random numbers based on stochastic values.
std::random_device pure_random_generator_;

//! Random generator that will not use seed (except at ctor) so always produces same random sequences.
std::mt19937 std_random_generator_;

/**
* @brief Random generator from a specific seed.
*
* @note using \c minstd_rand heads to seed 0 producing same value as seed 1.
* Also mt is faster.
*/
std::mt19937 seed_random_generator_;
};

} /* namespace utils */
} /* namespace eprosima */
143 changes: 143 additions & 0 deletions cpp_utils/include/cpp_utils/math/random/TSafeRandomManager.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed 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 TSafeRandomManager.hpp
*
* This file contains class TSafeRandomManager definition.
*/

#pragma once

#include <random>

#include <cpp_utils/library/library_dll.h>
#include <cpp_utils/math/random/RandomManager.hpp>
#include <cpp_utils/types/Atomicable.hpp>
#include <cpp_utils/types/Singleton.hpp>

namespace eprosima {
namespace utils {

/**
* @brief Object to manage the generation of random numbers in a thread environment.
*
* This class use different random generators from <random> library to obtain a complete random generator
* with multiple features:
* 1. Generate pure random numbers (no pseudorandom).
* 2. Generate an always equal random sequence from a seed.
* 3. Generate pseudorandom numbers from a specific seed (map each seed with always the same pseudorandom number).
* These 3 features are completely independent and calls between them do not affect each other.
*
* Motivation: Why use this class instead of a std::rand?
* The use of only rand and srand is not recommended by std (https://en.cppreference.com/w/cpp/numeric/random/rand).
* Also the use of rand does not allow to create pure random numbers (it must use srand with a explicit stochastic
* value as time(NULL) (that also can be repeated if executed in same second)) neither to keep state of random
* sequence once a seed has been used. This means that once using rand or srand in any part of the process, the
* random sequence will not be the same.
* Thus, this new class allow to get pure random numbers, get pseudorandom numbers from a seed and creating
* pseudorandom sequences without affecting the normal behaviour of rand and srand.
*
* @note this class is similar to \c RandomManager but thread-safe implementation
*/
class TSafeRandomManager
{
public:

/**
* @brief Construct a new Random Manager object.
*
* @param original_seed initial seed for sequence number generator.
*/
CPP_UTILS_DllAPI TSafeRandomManager(
const RandomSeedType& original_seed = 1);

//! Default destructor
CPP_UTILS_DllAPI ~TSafeRandomManager() = default;

/***********************
* NATIVE METHODS
***********************/
/**
* @brief Generate pure random number.
*
* Fulfill 1.
* This method does not affect the sequence generation numbers.
*
* @return Pure random number.
*/
CPP_UTILS_DllAPI RandomNumberType pure_rand () noexcept;

/**
* @brief Get next random number in pseudorandom sequence.
*
* Fulfill 2.
*
* @return Pure random number.
*/
CPP_UTILS_DllAPI RandomNumberType sequence_rand () noexcept;

//! Set seed for the sequence random series.
CPP_UTILS_DllAPI void seed (
const RandomSeedType& seed) noexcept;

/**
* @brief Get a random number related with a seed.
*
* Fulfill 3.
* This method does not affect the sequence generation numbers.
* This always returns the same random number for the same seed.
*
* @param seed to get random number.
*
* @return random number seeded by \c seed .
*/
CPP_UTILS_DllAPI RandomNumberType seeded_rand (
const RandomSeedType& seed) noexcept;


/***********************
* DERIVED METHODS
***********************/
// This methods only extend the API using the common word rand, but they only call native methods.

//! With Pure=true returns \c pure_rand . Otherwise returns \c sequence_rand .
template <bool Pure = false>
RandomNumberType rand () noexcept;

//! Return \c seeded_rand .
CPP_UTILS_DllAPI RandomNumberType rand (
const RandomSeedType& seed) noexcept;

protected:

/**
* @brief Generation of real random numbers based on stochastic values.
*
* @note this class is thread safe.
*/
std::random_device pure_random_generator_;

//! Random generator that will not use seed (except at ctor) so always produces same random sequences.
Atomicable<std::mt19937> std_random_generator_;

//! Random generator from a specific seed.
Atomicable<std::mt19937> seed_random_generator_;
};

//! Global singleton to use a ThreadSafeRandomManager in the whole process.
using GlobalRandomManager = Singleton<TSafeRandomManager, 42>;

} /* namespace utils */
} /* namespace eprosima */
3 changes: 1 addition & 2 deletions cpp_utils/include/cpp_utils/types/Atomicable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ namespace utils {
template <class Type, class Mutex = std::mutex>
class Atomicable : public Type, public Mutex
{
using Type::Type;
// Nothing to add
};

Expand All @@ -58,5 +59,3 @@ using SharedAtomicable = Atomicable<Type, std::shared_timed_mutex>;

} /* namespace utils */
} /* namespace eprosima */


Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
// limitations under the License.

/**
* @file math.cpp
* @file math_extension.cpp
*
*/

namespace eprosima {
namespace utils {

#include <assert.h>

#include <cpp_utils/math/math.hpp>
#include <cpp_utils/math/math_extension.hpp>

namespace eprosima {
namespace utils {

bool is_even(
unsigned int number) noexcept
Expand Down
Loading

0 comments on commit f97515a

Please sign in to comment.