uniform_sampling.hpp

Back to Uniform sampling

pastel/math/sampling/

#ifndef PASTELMATH_UNIFORM_SAMPLING_HPP
#define PASTELMATH_UNIFORM_SAMPLING_HPP

#include "pastel/sys/mytypes.h"
#include "pastel/sys/random.h"
#include "pastel/sys/ensure.h"
#include "pastel/sys/vector/vector_tools.h"

#include "pastel/math/sampling/uniform_sampling.h"

#include <cmath>

namespace Pastel
{

    template <typename Real, integer N>
    Vector<Real, N> randomVectorCube()
    {
        PASTEL_STATIC_ASSERT(N != Dynamic);
        return Pastel::randomVectorCube<Real, N>(N);
    }

    template <typename Real, integer N>
    Vector<Real, N> randomVectorCube(integer dimension)
    {
        PENSURE_OP(dimension, >=, 0);

        Vector<Real, N> direction(ofDimension(dimension));

        for (integer i = 0;i < dimension;++i)
        {
            direction[i] = 2 * random<Real>() - 1;
        }

        return direction;
    }

    template <typename Real, integer N>
    Vector<Real, N> randomVectorSphere()
    {
        PASTEL_STATIC_ASSERT(N != Dynamic);
        return Pastel::randomVectorSphere<Real, N>(N);
    }

    template <typename Real, integer N>
    Vector<Real, N> randomVectorSphere(integer dimension)
    {
        // A randomly distributed vector on the
        // unit sphere can be generated as follows.
        // A (0, v)-normal distribution is given by
        // f(x) = (1 / sqrt(v^2 2pi)) e^(-x^2/(2 v^2))
        // Pick n random variables from such a
        // distribution. Now
        // g(x_1, ..., x_n)
        // = f(x_1) ... f(x_n)
        // = (1 / sqrt(v^2 2pi))^n e^(-(x_1^2 + ... + x_n^2)/(2 v^2))
        // Which is again a distribution in R^n.
        // But the g distribution is only
        // dependent on the norm of X = (x_1, ..., x_n), not
        // on its direction, and thus the normalization of X
        // yields a uniformly distributed vector on the unit sphere.

        PENSURE_OP(dimension, >=, 0);

        Vector<Real, N> result(ofDimension(dimension));

        if (dimension > 0)
        {
            Real dotResult = 0;
            do
            {
                for (integer i = 0;i < dimension;++i)
                {
                    result[i] = randomGaussian<Real>();
                }
                dotResult = dot(result);
            }
            while(dotResult < 0.001);

            result /= std::sqrt(dotResult);
        }

        return result;
    }

    template <typename Real, integer N>
    Vector<Real, N> randomVectorBall()
    {
        PASTEL_STATIC_ASSERT(N != Dynamic);
        return Pastel::randomVectorBall<Real, N>(N);
    }

    template <typename Real, integer N>
    Vector<Real, N> randomVectorBall(
        integer dimension)
    {
        PENSURE_OP(dimension, >=, 0);

        Vector<Real, N> sphere = 
            randomVectorSphere<Real, N>(dimension);

        sphere *= std::pow(random<Real>(), inverse((Real)dimension));

        return sphere;
    }

    template <typename Real, integer N>
    Vector<Real, N> randomVectorAnnulus(
        const NoDeduction<Real>& minRadius,
        const NoDeduction<Real>& maxRadius)
    {
        PASTEL_STATIC_ASSERT(N != Dynamic);
        return Pastel::randomVectorAnnulus<Real, N>(
            minRadius, maxRadius, N);
    }

    template <typename Real, integer N>
    Vector<Real, N> randomVectorAnnulus(
        const NoDeduction<Real>& minRadius,
        const NoDeduction<Real>& maxRadius,
        integer dimension)
    {
        PENSURE_OP(dimension, >=, 0);

        Vector<Real, N> sphere = 
            randomVectorSphere<Real, N>(dimension);

        sphere *= 
            std::pow(
            linear(
            std::pow(minRadius, (Real)dimension), 
            std::pow(maxRadius, (Real)dimension), 
            random<Real>()),
            inverse((Real)dimension));

        return sphere;
    }

}

#endif