//==================================================================================================
// S t a t i s t i c s                                                                    Interface
// D i s t r i b u t i o n
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
// the GNU Library General Public License for more details (http://www.gnu.org).

/*DESCRIPTION*/
/* This module provides statistical distributions. Thanks to <A HREF="http://frog.isima.fr/soni/"
   TARGET="new_window">Soni</A> for helping me out with the formulas. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "statistics/distribution.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guStatisticsDistribution
#define guStatisticsDistribution

// Headers //---------------------------------------------------------------------------------------
#include <bpp/standard.hpp> /*INCLUDE*/

namespace bpp {

// Importation/Exportation //-----------------------------------------------------------------------
#ifdef STATISTICS_DLL
 #define dll_export DLL_EXPORT
#else
 #define dll_export DLL_IMPORT
#endif

// Namespaces //------------------------------------------------------------------------------------
#define public_area  statisticsDistribution
#define private_area statisticsDistribution_private

namespace public_area  { /*NAMESPACE*/ using namespace standard; }
namespace private_area { using namespace public_area; }

extern_module_name;

// Initialization //--------------------------------------------------------------------------------

// Macrocommands //---------------------------------------------------------------------------------

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------------------------------Classes
 class clDistribution;
 class clExponentialDistribution;
 class clNormalDistribution;
 class clUniformDistribution;
 //-----------------------------------------------------------------------------------Constant Types
 typedef const clDistribution            ctDistribution;
 typedef const clExponentialDistribution ctExponentialDistribution;
 typedef const clNormalDistribution      ctNormalDistribution;
 typedef const clUniformDistribution     ctUniformDistribution;
}

namespace private_area {}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Errors //----------------------------------------------------------------------------------------
namespace public_area {}

// Constants & Variables //-------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// D i s t r i b u t i o n  Interface //------------------------------------------------------------
namespace public_area {
 /*CLASS clDistribution */ /* Represents a statistical distribution. It is an abstract class. */
 class clDistribution {
  //-----------------------------------------------------------------------------------------Private
  private_property clRandomGenerator * atGenerator;
  private_property tyBoolean           atOwner;
  //------------------------------------------------------------------------------------------Public
  public_property constructor        clDistribution(void);
  public_property constructor        clDistribution(clRandomGenerator &);
  public_property constructor        clDistribution(ctDistribution &);
  public_property virtual destructor clDistribution(void);

  public_property clDistribution & operator = (ctDistribution &);

  /*AMETHOD clDistribution */ /* Returns the next value of the distribution. Abstract method. */
  public_property virtual tyReal next(void) = 0;
 };
}

// E x p o n e n t i a l D i s t r i b u t i o n  Interface //--------------------------------------
namespace public_area {
 /*CLASS clExponentialDistribution */
 /* Represents an exponential distribution with parameter <I>lambda</I>. Its mean value is
    <I>1/lambda</I> and its variance is <I>1/(lambda*lambda)</I>. */
 class clExponentialDistribution : public clDistribution {
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clExponentialDistribution */
  /* Parameter <I>lambda</I> of the exponential distribution. It is the inverse of the mean value
     of the distribution. */
  read_write_attribute(tyReal,atLambda,lambda);

  public_property constructor clExponentialDistribution(tyReal=1.0);
  public_property constructor clExponentialDistribution(clRandomGenerator &,tyReal=1.0);
  public_property constructor clExponentialDistribution(ctExponentialDistribution &);
  public_property destructor  clExponentialDistribution(void);

  public_property clExponentialDistribution & operator = (ctExponentialDistribution &);

  public_property tyReal next(void);
 };
}

// N o r m a l D i s t r i b u t i o n  Interface //------------------------------------------------
namespace public_area {
 /*CLASS clNormalDistribution */
 /* Represents a normal distribution. Its parameters are its mean and its variance. */
 class clNormalDistribution : public clDistribution {
  //-----------------------------------------------------------------------------------------Private
  private_property tyReal    atNextValue;
  private_property tyReal    atStandardDeviation;
  private_property tyBoolean atUseNext;
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clNormalDistribution */ /* Mean of the distribution. */
  read_write_attribute(tyReal,atMean,mean);

  /*ATTRIBUTE clNormalDistribution */ /* Variance of the distribution. */
  read_only_attribute(tyReal,atVariance,variance);

  public_property constructor clNormalDistribution(tyReal=0.0,tyReal=1.0);
  public_property constructor clNormalDistribution(clRandomGenerator &,tyReal=0.0,tyReal=1.0);
  public_property constructor clNormalDistribution(ctNormalDistribution &);
  public_property destructor  clNormalDistribution(void);

  public_property clNormalDistribution & operator = (ctNormalDistribution &);

  public_property tyReal   next(void);
  public_property tyReal & variance(void);
 };
}

// U n i f o r m D i s t r i b u t i o n  Interface //----------------------------------------------
namespace public_area {
 /*CLASS clUniformDistribution */
 /* Represents a uniform distribution with parameters <I>a</I> and <I>b</I>. Its mean value is
    <I>(a+b)/2</I> and its variance is <I>(b-a)(b-a)/12</I>. */
 class clUniformDistribution : public clDistribution {
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clUniformDistribution */
  /* Parameter <I>a</I>, minimum value generated by the distribution. */
  read_write_attribute(tyReal,atMinimum,minimum);

  /*ATTRIBUTE clUniformDistribution */
  /* Parameter <I>b</I>, maximum value generated by the distribution. */
  read_write_attribute(tyReal,atMaximum,maximum);

  public_property constructor clUniformDistribution(tyReal=0.0,tyReal=1.0);
  public_property constructor clUniformDistribution(clRandomGenerator &,tyReal=0.0,tyReal=1.0);
  public_property constructor clUniformDistribution(ctUniformDistribution &);
  public_property destructor  clUniformDistribution(void);

  public_property clUniformDistribution & operator = (ctUniformDistribution &);

  public_property tyReal next(void);
 };
}

// Functions Inline //------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// D i s t r i b u t i o n  Inline //---------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clDistribution */
 /* Builds a statistical distribution with its own random number generator. */
 inline clDistribution::clDistribution(void) : atGenerator(nil),atOwner(true)
 { atGenerator=new_object(clRandomGenerator(randomCardinal(cardinalMax()))); }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clDistribution */
 /* Builds a statistical distribution based on a given random number generator. */
 inline clDistribution::clDistribution(clRandomGenerator & agGenerator)
 : atGenerator(&agGenerator),atOwner(false) {}
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clDistribution */
 /* Builds a statistical distribution by copying another one. If the original distribution has its
    own random generator instance, then a generator is instantiated for the copy, else the copy
    uses the random generator of the original distribution. */
 inline clDistribution::clDistribution(const clDistribution & agDistribution)
 : atGenerator(nil),atOwner(agDistribution.atOwner) {
  if (atOwner) atGenerator=new_object(clRandomGenerator(randomCardinal(cardinalMax())));
  else atGenerator=agDistribution.atGenerator;
 }
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clDistribution */ /* Destructs the distribution. */
 inline clDistribution::~clDistribution(void)
 { if (atOwner and atGenerator!=nil) delete_object(atGenerator); }
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clDistribution */
 /* Copies a distribution. If the original distribution has its own random generator instance,
    then a generator is instantiated for the copy, else the copy uses the random generator
    of the original distribution. */
 inline clDistribution & clDistribution::operator = (ctDistribution & agDistribution) {
  if (atOwner and atGenerator!=nil) delete_object(atGenerator);
  atOwner=agDistribution.atOwner;

  if (atOwner) atGenerator=new_object(clRandomGenerator(randomCardinal(cardinalMax())));
  else atGenerator=agDistribution.atGenerator;

  return (*this);
 }
}

// E x p o n e n t i a l D i s t r i b u t i o n  Inline //-----------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clExponentialDistribution */
 /* Builds an exponential distribution with its own random number generator. The parameter
    <I>lambda</I> of the distribution must be given (default is 1.0). */
 inline clExponentialDistribution::clExponentialDistribution(tyReal agLambda)
 : clDistribution(),atLambda(agLambda) {}
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clExponentialDistribution */
 /* Builds an exponential distribution based on a given random number generator. The parameter
    <I>lambda</I> of the distribution must be given (default is 1.0). */
 inline clExponentialDistribution::clExponentialDistribution(clRandomGenerator & agGenerator,
                                                             tyReal agLambda)
 : clDistribution(agGenerator),atLambda(agLambda) {}
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clExponentialDistribution */
 /* Builds an exponential distribution by copying another one. */
 inline
 clExponentialDistribution::clExponentialDistribution (ctExponentialDistribution & agDistribution)
 : clDistribution(agDistribution),atLambda(agDistribution.atLambda) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clExponentialDistribution */ /* Destructs the distribution. */
 inline clExponentialDistribution::~clExponentialDistribution(void) {}
}

// N o r m a l D i s t r i b u t i o n  Inline //---------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clNormalDistribution */
 /* Builds a normal distribution with its own random number generator. The mean and the variance
    of the distribution must be given (defaults are respectively 0.0 and 1.0). */
 inline clNormalDistribution::clNormalDistribution(tyReal agMean,tyReal agVariance)
 : clDistribution(),atNextValue(0.0),atStandardDeviation(0.0),atUseNext(false),atMean(agMean),
   atVariance(agVariance) { atStandardDeviation=std::sqrt(atVariance); }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clNormalDistribution */
 /* Builds a normal distribution based on a given random number generator. The mean and the variance
    of the distribution must be given (defaults are respectively 0.0 and 1.0). */
 inline clNormalDistribution::clNormalDistribution(clRandomGenerator & agGenerator,
                                                   tyReal agMean,tyReal agVariance)
 : clDistribution(agGenerator),atNextValue(0.0),atStandardDeviation(0.0),atUseNext(false),
   atMean(agMean),atVariance(agVariance) { atStandardDeviation=std::sqrt(atVariance); }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clNormalDistribution */ /* Builds a normal distribution by copying another one. */
 inline clNormalDistribution::clNormalDistribution(ctNormalDistribution & agDistribution)
 : clDistribution(agDistribution),atNextValue(0.0),atStandardDeviation(0.0),atUseNext(false),
   atMean(agDistribution.mean()),atVariance(agDistribution.variance())
 { atStandardDeviation=std::sqrt(atVariance); }
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clNormalDistribution */ /* Destructs the distribution. */
 inline clNormalDistribution::~clNormalDistribution(void) {}
 //-----------------------------------------------------------------------------------------Variance
 /*METHOD clNormalDistribution */
 /* Returns the variance of the distribution. Read-write version. */
 inline tyReal & clNormalDistribution::variance(void) { return (atVariance); }
}

// U n i f o r m D i s t r i b u t i o n  Inline //-------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clUniformDistribution */
 /* Builds a uniform distribution with its own random number generator. The two parameters <I>a</I>
    and <I>b</I> of the distribution must be given (defaults are respectively 0.0 and 1.0). */
 inline clUniformDistribution::clUniformDistribution(tyReal agMinimum,tyReal agMaximum)
 : clDistribution(),atMinimum(agMinimum),atMaximum(agMaximum) {}
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clUniformDistribution */
 /* Builds a uniform distribution based on a given random number generator. The two parameters
    <I>a</I> and <I>b</I> of the distribution must be given
    (defaults are respectively 0.0 and 1.0). */
 inline clUniformDistribution::clUniformDistribution(clRandomGenerator & agGenerator,
                                                     tyReal agMinimum,tyReal agMaximum)
 : clDistribution(agGenerator),atMinimum(agMinimum),atMaximum(agMaximum) {}
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clUniformDistribution */ /* Builds a uniform distribution by copying another one. */
 inline clUniformDistribution::clUniformDistribution(ctUniformDistribution & agDistribution)
 : clDistribution(agDistribution),atMinimum(agDistribution.minimum()),
   atMaximum(agDistribution.maximum()) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clUniformDistribution */ /* Destructs the distribution. */
 inline clUniformDistribution::~clUniformDistribution(void) {}
}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef public_area
#undef private_area
#endif
 
//==================================================================================================
// S t a t i s t i c s                                                               Implementation
// D i s t r i b u t i o n
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
// the GNU Library General Public License for more details (http://www.gnu.org).

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "statistics/distribution.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define MODEL_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/statistics/distribution.hpp> /*INTERFACE*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  statisticsDistribution
#define private_area statisticsDistribution_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Statistics/Distribution");

// Initialization //--------------------------------------------------------------------------------

// Errors //----------------------------------------------------------------------------------------
namespace public_area {}

// Constants & Variables //-------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Static Members //--------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// E x p o n e n t i a l D i s t r i b u t i o n  Implementation //---------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clExponentialDistribution */ /* Copies an exponential distribution. */
 property clExponentialDistribution &
 clExponentialDistribution::operator = (ctExponentialDistribution & agDistribution) {
  clDistribution::operator=(agDistribution);
  atLambda=agDistribution.lambda();

  return (*this);
 }
 //---------------------------------------------------------------------------------------------Next
 /*METHOD clExponentialDistribution */ /* Returns the next value of the distribution. */
 property tyReal clExponentialDistribution::next(void)
 { return (-std::log(1-atGenerator->nextFloorReal())/atLambda); }
}

// N o r m a l D i s t r i b u t i o n  Implementation //-------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clNormalDistribution */ /* Copies a normal distribution. */
 property
 clNormalDistribution & clNormalDistribution::operator = (ctNormalDistribution & agDistribution) {
  clDistribution::operator=(agDistribution);
  atNextValue=0.0;
  atStandardDeviation=std::sqrt(agDistribution.variance());
  atUseNext=false;
  atMean=agDistribution.mean();
  atVariance=agDistribution.variance();

  return (*this);
 }
 //---------------------------------------------------------------------------------------------Next
 /*METHOD clNormalDistribution */
 /* Returns the next value of the distribution, using
    <A HREF="http://mathworld.wolfram.com/Box-MullerTransformation.html"
    TARGET="new_window">Box-Muller transformation</A>. */
 property tyReal clNormalDistribution::next(void) {
  if (atUseNext) {
   atUseNext=false;
   return (atNextValue*atStandardDeviation+atMean);
  }
  else {
   tyReal lcX1;
   tyReal lcX2;
   tyReal lcW;

   do {
    lcX1=2.0*atGenerator->nextReal()-1.0;
    lcX2=2.0*atGenerator->nextReal()-1.0;
    lcW=lcX1*lcX1+lcX2*lcX2;
   }
   while (lcW>=1 or lcW==0);

   lcW=std::sqrt(-2.0*std::log(lcW)/lcW);
   atNextValue=lcX2*lcW;
   atUseNext=true;
   return (lcX1*lcW*atStandardDeviation+atMean);
  }
 }
}

// U n i f o r m D i s t r i b u t i o n  Implementation //-----------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clUniformDistribution */ /* Copies a uniform distribution. */
 property clUniformDistribution &
 clUniformDistribution::operator = (ctUniformDistribution & agDistribution) {
  clDistribution::operator=(agDistribution);
  atMinimum=agDistribution.minimum();
  atMaximum=agDistribution.maximum();

  return (*this);
 }
 //---------------------------------------------------------------------------------------------Next
 /*METHOD clUniformDistribution */ /* Returns the next value of the distribution. */
 property tyReal clUniformDistribution::next(void)
 { return (minimum()+(maximum()-minimum())*atGenerator->nextReal()); }
}

// End //-------------------------------------------------------------------------------------------
}