/*
    Copyright (2001) Ascent Software Ltd.
    Contact: Chris McGinlay, Roselynn, Levenwick, Shetland, UK, ZE2 9HX.

    This file is part of the Probability Distribution Namespace (version AUG2001).     
    
    Probability Distribution Namespace (version AUG2001) is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.     
    
    Probability Distribution Namespace (version AUG2001) 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 General Public License for more details.     
    
    You should have received a copy of the GNU General Public License
    along with Probability Distribution Namespace (version AUG2001); if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/************************************
  REVISION LOG ENTRY
  Revision By: Chris McGinlay
  Revised on 01/08/01 13:20:41
  Comments: adding Binomial class
 ************************************/

 /************************************
  CREATION LOG ENTRY
  CREATED BY: Chris McGinlay
  CREATED ON: 17/07/01 21:24:20
  Comments: Header file for random classes
 ************************************/

#include <vector>
#include <cmath>

namespace Probability_Distribution
{
    //exception class
    class Bad_Distribution {};

    //distribution class to serve as base class
    class Distribution
    {
    public:
        //operations
        virtual long draw() const =0;           //draw one number from distribution
        virtual double mean() const =0;
        virtual double variance() const =0;
        virtual void test(int n) const =0;       //test distribution by performing n draws
        virtual ~Distribution() {};
    };

    //uniformly distributed discrete random variable on [lo, hi]
    class Uniform : public Distribution
    {
    private:
        long _lo_bound;     //lower bound of distribution
        long _up_bound;     //upper bound of distribution
        long _width;        //difference between upper and lower bounds
        static Uniform default_distrib;

    public:
        Uniform(long lo=0, long hi=0, long seed=0);
        inline ~Uniform(){};

        //accessors
        inline long lo_bound() const {return _lo_bound;}
        inline long up_bound() const {return _up_bound;}
        inline double mean() const {return double(_up_bound-_lo_bound+1);}
        inline double variance() const{return (pow((_up_bound-_lo_bound-2),2) /12);}

        //operations
        long draw() const;  //draw from uniform dist   
        static void set_default(int lo, int hi);
        void test(int n=10000) const;   //default arguments need not be the same in each subclass
    };

    //binomially distributed discrete random variable on [lo, hi]
    class Binomial
    {
    private:
        int _n;         //number of trials
        double _p;      //probability of success in one trial
        std::vector<int> _bucket;   //scaled bucket widths
        static const Uniform _u;          //uniform distribution for internal use
        static Binomial default_distrib;
        static long const _long_max;    //max size of long type

    public:
        Binomial(int n=0, double p=0, long seed=0);
        inline ~Binomial(){};

        //accessors
        inline int n() const {return _n;}
        inline double p() const {return _p;}
        inline double mean() const {return double(_n)*_p;}
        inline double variance() const {return double(_n)*_p*(1-_p);}

        //operations
        long draw() const;  //draw returns number of successes in n trials
        static void set_default(int n, double p);
        void test(int n=10000) const;   //default arguments need not be the same in each subclass

    };

    //poisson distribution
    class Poisson
    {
    private:
        double _mu;       //mean of distribution (sole parameter)
        std::vector<long> _bucket;   //scaled bucket widths
        static const Uniform _u;          //uniform distribution for internal use
        static Poisson default_distrib;
        static long const _long_max;    //max size of long type

    public:
        Poisson(double mu=0, long seed=0);
        inline ~Poisson(){};

        //accessors
        inline double mean() const {return _mu;}
        inline double variance() const {return _mu;}

        //operations
        long draw() const;  //draw returns number of successes in n trials
        static void set_default(double mu);
        void test(int n=10000) const;   //default arguments need not be the same in each subclass
    };

    //helper functions
    long bincoff(int n, int r);     //compute binomial co-efficient
    long double factorial(int n);          //compute factorial
    long double factorial(int top, int bot);//top!/bot!
};