diff --git a/doc/manual/source/random-variables.rst b/doc/manual/source/random-variables.rst index ed6e9afc3..ecba18981 100644 --- a/doc/manual/source/random-variables.rst +++ b/doc/manual/source/random-variables.rst @@ -263,6 +263,7 @@ can also create their own custom random variables by deriving from class * class :cpp:class:`EmpiricalRandomVariable` * class :cpp:class:`BinomialRandomVariable` * class :cpp:class:`BernoulliRandomVariable` +* class :cpp:class:`LaplacianRandomVariable` Semantics of RandomVariableStream objects ***************************************** diff --git a/src/core/model/random-variable-stream.cc b/src/core/model/random-variable-stream.cc index 699f98242..bc66439c7 100644 --- a/src/core/model/random-variable-stream.cc +++ b/src/core/model/random-variable-stream.cc @@ -33,6 +33,7 @@ #include "rng-seed-manager.h" #include "rng-stream.h" #include "string.h" +#include "uinteger.h" #include // upper_bound #include @@ -1871,4 +1872,111 @@ BernoulliRandomVariable::GetValue() return GetValue(m_probability); } +NS_OBJECT_ENSURE_REGISTERED(LaplacianRandomVariable); + +TypeId +LaplacianRandomVariable::GetTypeId() +{ + static TypeId tid = + TypeId("ns3::LaplacianRandomVariable") + .SetParent() + .SetGroupName("Core") + .AddConstructor() + .AddAttribute("Location", + "The location parameter for the Laplacian distribution returned by this " + "RNG stream.", + DoubleValue(0.0), + MakeDoubleAccessor(&LaplacianRandomVariable::m_location), + MakeDoubleChecker()) + .AddAttribute( + "Scale", + "The scale parameter for the Laplacian distribution returned by this RNG stream.", + DoubleValue(1.0), + MakeDoubleAccessor(&LaplacianRandomVariable::m_scale), + MakeDoubleChecker()) + .AddAttribute("Bound", + "The bound on the values returned by this RNG stream.", + DoubleValue(0.0), + MakeDoubleAccessor(&LaplacianRandomVariable::m_bound), + MakeDoubleChecker()); + return tid; +} + +LaplacianRandomVariable::LaplacianRandomVariable() +{ + NS_LOG_FUNCTION(this); +} + +double +LaplacianRandomVariable::GetLocation() const +{ + return m_location; +} + +double +LaplacianRandomVariable::GetScale() const +{ + return m_scale; +} + +double +LaplacianRandomVariable::GetBound() const +{ + return m_bound; +} + +double +LaplacianRandomVariable::GetValue(double location, double scale, double bound) +{ + NS_LOG_FUNCTION(this << location << scale << bound); + NS_ABORT_MSG_IF(scale <= 0, "Scale parameter should be larger than 0"); + + while (true) + { + // Get a uniform random variable in [-0.5,0.5]. + auto v = (Peek()->RandU01() - 0.5); + if (IsAntithetic()) + { + v = (1 - v); + } + + // Calculate the laplacian random variable. + const auto sgn = (v > 0) ? 1 : ((v < 0) ? -1 : 0); + const auto r = location - (scale * sgn * std::log(1.0 - (2.0 * std::abs(v)))); + + // Use this value if it's acceptable. + if (bound == 0.0 || std::fabs(r - location) <= bound) + { + return r; + } + } +} + +uint32_t +LaplacianRandomVariable::GetInteger(uint32_t location, uint32_t scale, uint32_t bound) +{ + NS_LOG_FUNCTION(this << location << scale << bound); + return static_cast(GetValue(location, scale, bound)); +} + +double +LaplacianRandomVariable::GetValue() +{ + NS_LOG_FUNCTION(this); + return GetValue(m_location, m_scale, m_bound); +} + +double +LaplacianRandomVariable::GetVariance(double scale) +{ + NS_LOG_FUNCTION(scale); + return 2.0 * std::pow(scale, 2.0); +} + +double +LaplacianRandomVariable::GetVariance() const +{ + return GetVariance(m_scale); +} + } // namespace ns3 diff --git a/src/core/model/random-variable-stream.h b/src/core/model/random-variable-stream.h index 01bffd629..abe8d3a4d 100644 --- a/src/core/model/random-variable-stream.h +++ b/src/core/model/random-variable-stream.h @@ -2284,6 +2284,112 @@ class BernoulliRandomVariable : public RandomVariableStream }; // class BernoulliRandomVariable +/** + * \ingroup randomvariable + * \brief The laplacian distribution Random Number Generator (RNG). + * + * This class supports the creation of objects that return random numbers + * from a fixed laplacian distribution. + * + * The probability density function of a laplacian variable + * is defined as: + * + * \f[ + * P(x; \mu, \beta) dx = \frac{1}{2 \beta} e^{\frac{- \abs{x - \mu}}{\beta}} dx + * \f] + * + * where \f$\mu\f$ is the \c Location configurable attribute and \f$\beta\f$ + * is the \c Scale configurable attribute. This distribution has mean \f$\mu\f$ + * and variance \f$ \sigma^2 = 2 \beta^2 \f$. + * + * The laplacian RNG value \f$x\f$ is generated by + * + * \f[ + * x = \mu - \beta sgn(u) \log(1 - 2 \abs{u}) + * \f] + * + * where \f$u\f$ is a uniform random variable on [-0.5,0.5). + * + * \par Bounded Distribution + * + * The Laplacian distribution can be bounded symmetrically about the mean by + * the \c Bound parameter, \f$b\f$, _i.e._ its values are confined to the interval + * \f$[\mu - b, \mu + b]\f$. This preserves the mean but decreases the variance. + */ +class LaplacianRandomVariable : public RandomVariableStream +{ + public: + /** + * \brief Register this type. + * \return The object TypeId. + */ + static TypeId GetTypeId(); + + /** + * \brief Creates an unbounded laplacian distribution RNG with the default + * values for the location and the scale. + */ + LaplacianRandomVariable(); + + /** + * \brief Get the configured location value of this RNG. + * + * \return The configured location value. + */ + double GetLocation() const; + + /** + * \brief Get the configured scale value of this RNG. + * + * \return The configured scale value. + */ + double GetScale() const; + + /** + * \brief Get the configured bound of this RNG. + * \return The bound. + */ + double GetBound() const; + + /** + * \copydoc GetValue() + * \param [in] location location value of the laplacian distribution. + * \param [in] scale scale value of the laplacian distribution. + * \param [in] bound bound on values returned. + */ + double GetValue(double location, double scale, double bound); + + /** \copydoc GetValue(double,double,double) */ + uint32_t GetInteger(uint32_t location, uint32_t scale, uint32_t bound); + + // Inherited + double GetValue() override; + using RandomVariableStream::GetInteger; + + /** + * \brief Returns the variance value for the laplacian distribution returned by this RNG stream. + * \return The variance value for the laplacian distribution returned by this RNG stream. + */ + double GetVariance() const; + + /** + * \copydoc GetVariance() + * \param [in] scale scale value of the laplacian distribution. + */ + static double GetVariance(double scale); + + private: + /** The location value of the laplacian distribution. */ + double m_location; + + /** The scale value of the laplacian distribution. */ + double m_scale; + + /** The bound on values that can be returned by this RNG stream. */ + double m_bound; + +}; // class LaplacianRandomVariable + } // namespace ns3 #endif /* RANDOM_VARIABLE_STREAM_H */