Gamma.h
Go to the documentation of this file.
1 /*!
2  *
3  *
4  * \brief Implements a Gamma distribution.
5  *
6  *
7  *
8  * \author O. Krause
9  * \date 2010-01-01
10  *
11  *
12  * \par Copyright 1995-2017 Shark Development Team
13  *
14  * <BR><HR>
15  * This file is part of Shark.
16  * <http://shark-ml.org/>
17  *
18  * Shark is free software: you can redistribute it and/or modify
19  * it under the terms of the GNU Lesser General Public License as published
20  * by the Free Software Foundation, either version 3 of the License, or
21  * (at your option) any later version.
22  *
23  * Shark is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26  * GNU Lesser General Public License for more details.
27  *
28  * You should have received a copy of the GNU Lesser General Public License
29  * along with Shark. If not, see <http://www.gnu.org/licenses/>.
30  *
31  */
32 #ifndef SHARK_RNG_GAMMA_H
33 #define SHARK_RNG_GAMMA_H
34 
35 
36 
37 #include <boost/random/uniform_01.hpp>
38 #include <cmath>
39 
40 #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
41 #include <iostream>
42 #endif
43 
44 namespace shark{
45 /// Gamma distribution.
46 template<class RealType = double>
48  {
49  public:
50  typedef RealType input_type;
51  typedef RealType result_type;
52 
53  explicit Gamma_distribution(RealType k,RealType theta)
54  :k_(k),theta_(theta) {}
55 
56  RealType k() const
57  {
58  return k_;
59  }
60  RealType theta()const
61  {
62  return theta_;
63  }
64 
65  void reset() { }
66 
67  template<class Engine>
68  result_type operator()(Engine& eng)
69  {
70  unsigned i;
71  unsigned n = unsigned(k_);
72  RealType delta = k_ - RealType(n);
73  RealType V_2, V_1, V;
74  RealType v0 = M_E / (M_E + delta);
75  RealType eta, xi;
76  RealType Gn1 = 0; // Gamma(n, 1) distributed
77 
78  for(i=0; i<n; i++) Gn1 += -log(draw(eng));
79 
80  do {
81  V_2 = draw(eng);
82  V_1 = draw(eng);
83  V = draw(eng);
84  if(V_2 <= v0)
85  {
86  xi = pow(V_1, 1./delta);
87  eta = V * pow(xi, delta-1.);
88  }
89  else
90  {
91  xi = 1. - log(V_1);
92  eta = V * exp(-xi);
93  }
94  } while(eta > (pow(xi, delta-1.) * exp(-xi)));
95 
96  return theta_ * (xi + Gn1);
97  }
98 
99 #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
100  template<class CharT, class Traits>
101  friend std::basic_ostream<CharT,Traits>&
102  operator<<(std::basic_ostream<CharT,Traits>& os, const Gamma_distribution& gd)
103  {
104  os << gd.k_;
105  os << gd.theta_;
106  return os;
107  }
108 
109  template<class CharT, class Traits>
110  friend std::basic_istream<CharT,Traits>&
111  operator>>(std::basic_istream<CharT,Traits>& is, Gamma_distribution& gd)
112  {
113  is >> gd.k_;
114  is >> gd.theta_;
115  return is;
116  }
117 #endif
118  private:
119  template<class Engine>
120  double draw(Engine& eng)
121  {
122  double res=0;
123  do
124  {
125  res=boost::uniform_01<RealType>()(eng);
126  }
127  while(res==0);
128  return res;
129  }
130  double k_;
131  double theta_;
132  };
133 
134 /// Gamma distributed random variable.
135 template<typename RngType = shark::DefaultRngType>
136 class Gamma:public boost::variate_generator<RngType*,Gamma_distribution<> >
137  {
138  private:
139  typedef boost::variate_generator<RngType*,Gamma_distribution<> > Base;
140  public:
141 
142  explicit Gamma( RngType & rng, double k=1,double theta=1 )
143  :Base(&rng,Gamma_distribution<>(k,theta))
144  {}
145 
146  using Base::operator();
147 
148  double operator()(double k,double theta)
149  {
150  Gamma_distribution<> dist(k,theta);
151  return dist(Base::engine());
152  }
153 
154  double k()const
155  {
156  return Base::distribution().k();
157  }
158  double theta()const
159  {
160  return Base::distribution().theta();
161  }
162  void k(double newK)
163  {
164  Base::distribution()=Gamma_distribution<>(newK,theta());
165  }
166  void theta(double newTheta)
167  {
168  Base::distribution()=Gamma_distribution<>(k(),newTheta);
169  }
170 
171  double p(double x)const
172  {
173  // return std::pow(x, k()-1) * std::exp(-x / theta()) / (shark::gamma(k()) * std::pow(theta(), k())); // CI
174  return std::pow(x, k()-1) * std::exp(-x / theta()) / (Gamma_distribution<>(k()) * std::pow(theta(), k()));
175  }
176 
177  };
178 }
179 #endif