Browse Source

Merge ac524724bc into b5dead9223

pull/432/merge
sariug 6 years ago committed by GitHub
parent
commit
0de3e9fa9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      src/Magnum/Math/CMakeLists.txt
  2. 100
      src/Magnum/Math/Random.h
  3. 6
      src/Magnum/Math/Test/CMakeLists.txt
  4. 101
      src/Magnum/Math/Test/RandomTest.cpp

1
src/Magnum/Math/CMakeLists.txt

@ -49,6 +49,7 @@ set(MagnumMath_HEADERS
Quaternion.h Quaternion.h
Packing.h Packing.h
PackingBatch.h PackingBatch.h
Random.h
Range.h Range.h
RectangularMatrix.h RectangularMatrix.h
StrictWeakOrdering.h StrictWeakOrdering.h

100
src/Magnum/Math/Random.h

@ -0,0 +1,100 @@
#ifndef Magnum_Math_Random_h
#define Magnum_Math_Random_h
// TO DO Licence things.
#include <random>
#include <chrono>
#include "Magnum/Types.h"
#include "Magnum/Math/Constants.h"
#include "Magnum/Math/Vector2.h"
#include "Magnum/Math/Vector3.h"
#include "Magnum/Math/Quaternion.h"
#include "Magnum/Math/Functions.h"
namespace Magnum
{
namespace Math
{
namespace Random
{
class RandomGenerator
{
public:
RandomGenerator()
{
std::seed_seq seeds{{
static_cast<std::uintmax_t>(std::random_device{}()),
static_cast<std::uintmax_t>(std::chrono::steady_clock::now()
.time_since_epoch()
.count()),
}};
g = std::mt19937{seeds};
};
template <typename T>
typename std::enable_if<std::is_same<Int, T>::value, T>::type
generate(T start = -Magnum::Math::Constants<T>::inf(),
T end = Magnum::Math::Constants<T>::inf())
{
return std::uniform_int_distribution<T>{start, end}(g);
}
template <typename T>
typename std::enable_if<std::is_same<Float, T>::value, T>::type
generate(T start = -Magnum::Math::Constants<T>::inf(),
T end = Magnum::Math::Constants<T>::inf())
{
return std::uniform_real_distribution<T>{start, end}(g);
}
private:
// namespace Implementation
std::mt19937 g;
};
template <class T = Float>
T randomScalar(RandomGenerator &g, T begin = 0.0f, T end = 1.0f)
{
return g.generate(static_cast<T>(begin),
static_cast<T>(end));
}
template <class T = Float>
Vector2<T> randomUnitVector2(RandomGenerator &g)
{
auto a = g.generate(0.0f, 2 * Math::Constants<T>::pi());
return {std::cos(a), std::sin(a)};
}
template <class T = Float>
Vector3<T> randomUnitVector3(RandomGenerator &g)
{
// Better to have it "theta" and "z" than three random numbers.
// https://mathworld.wolfram.com/SpherePointPicking.html
auto a = g.generate(0.0f, 2 * Math::Constants<T>::pi());
auto z = randomScalar(g, -1.0f, -1.0f);
auto r = sqrt<T>(1 - z * z);
return {r * std::cos(a), r * std::sin(a), z};
}
template <class T = Float>
Quaternion<T> randomRotation(RandomGenerator &g)
{
//http://planning.cs.uiuc.edu/node198.html
auto u = randomScalar(g);
auto v = 2 * Math::Constants<T>::pi() * randomScalar(g);
auto w = 2 * Math::Constants<T>::pi() * randomScalar(g);
return Quaternion<T>({sqrt<T>(1 - u) * std::sin(v),
sqrt<T>(1 - u) * std::cos(v),
sqrt<T>(u) * std::sin(w)},
sqrt<T>(u) * std::cos(w));
}
} // namespace Random
} // namespace Math
} // namespace Magnum
#endif

6
src/Magnum/Math/Test/CMakeLists.txt

@ -71,6 +71,8 @@ corrade_add_test(MathStrictWeakOrderingTest StrictWeakOrderingTest.cpp LIBRARIES
corrade_add_test(MathVectorBenchmark VectorBenchmark.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(MathVectorBenchmark VectorBenchmark.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathMatrixBenchmark MatrixBenchmark.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(MathMatrixBenchmark MatrixBenchmark.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathRandomTest RandomTest.cpp LIBRARIES MagnumMathTestLib)
set_property(TARGET set_property(TARGET
MathVectorTest MathVectorTest
MathMatrixTest MathMatrixTest
@ -86,6 +88,8 @@ set_property(TARGET
MathDistanceTest MathDistanceTest
MathIntersectionTest MathIntersectionTest
MathRandomTest
APPEND PROPERTY COMPILE_DEFINITIONS "CORRADE_GRACEFUL_ASSERT") APPEND PROPERTY COMPILE_DEFINITIONS "CORRADE_GRACEFUL_ASSERT")
set_target_properties( set_target_properties(
@ -131,4 +135,6 @@ set_target_properties(
MathConfigurationValueTest MathConfigurationValueTest
MathStrictWeakOrderingTest MathStrictWeakOrderingTest
MathRandomTest
PROPERTIES FOLDER "Magnum/Math/Test") PROPERTIES FOLDER "Magnum/Math/Test")

101
src/Magnum/Math/Test/RandomTest.cpp

@ -0,0 +1,101 @@
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Numeric.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Math/Random.h"
namespace Magnum
{
namespace Math
{
namespace Test
{
namespace
{
struct RandomTest : Corrade::TestSuite::Tester
{
explicit RandomTest();
void randScalar();
void unitVector2();
void unitVector3();
void randomRotation();
void randomDiceChiSquare();
};
typedef Vector<2, Float> Vector2;
typedef Vector<3, Float> Vector3;
typedef Math::Constants<Float> Constants;
RandomTest::RandomTest()
{
Corrade::TestSuite::Tester::addRepeatedTests(
{&RandomTest::randScalar,
&RandomTest::unitVector2,
&RandomTest::unitVector3,
&RandomTest::randomRotation},
/*repeat number*/ 200);
Corrade::TestSuite::Tester::addTests(
{&RandomTest::randomDiceChiSquare});
}
void RandomTest::randScalar()
{
Math::Random::RandomGenerator g;
CORRADE_COMPARE_AS(Math::Random::randomScalar<Float>(g, -1.0, 1.0), 1.0f, Corrade::TestSuite::Compare::LessOrEqual);
CORRADE_COMPARE_AS(Math::Random::randomScalar<Float>(g, -1.0, 1.0), -1.0f, Corrade::TestSuite::Compare::GreaterOrEqual);
}
void RandomTest::unitVector2()
{
Math::Random::RandomGenerator g;
CORRADE_COMPARE((Math::Random::randomUnitVector2(g)).length(), 1.0f);
}
void RandomTest::unitVector3()
{
Math::Random::RandomGenerator g;
CORRADE_COMPARE((Math::Random::randomUnitVector3(g)).length(), 1.0f);
}
void RandomTest::randomRotation()
{
Math::Random::RandomGenerator g;
CORRADE_COMPARE(Math::Random::randomRotation(g).length(), 1.0f);
}
void RandomTest::randomDiceChiSquare()
{
// A step by step explanation
// https://rpg.stackexchange.com/questions/70802/how-can-i-test-whether-a-die-is-fair
Math::Random::RandomGenerator g;
int error_count = 0; // We have 1 chance to over shoot. Thats why no repeated test.
const Int dice_side = 20;
const Int expected = 10000;
const Float thresholdfor100 = 36.191;
for (auto i = 0; i < 100; i++)
{
std::vector<Int> faces(dice_side, 0);
for (std::size_t i = 0; i < expected * dice_side; i++)
faces[Math::Random::randomScalar<Int>(g, 0, dice_side - 1)]++;
Float chi_square = 0.0f;
for (std::size_t i = 0; i < dice_side; i++)
chi_square += Float(pow((faces[i] - expected), 2)) / expected;
if (chi_square > thresholdfor100)
error_count++;
}
CORRADE_COMPARE_AS(error_count, 2, Corrade::TestSuite::Compare::Less);
}
} // namespace
} // namespace Test
} // namespace Math
} // namespace Magnum
CORRADE_TEST_MAIN(Magnum::Math::Test::RandomTest)
Loading…
Cancel
Save