ANIMA  4.0
animaKummerFunctions.cxx
Go to the documentation of this file.
1 #include <animaKummerFunctions.h>
2 #include <boost/math/quadrature/gauss.hpp>
3 #include <itkMacro.h>
4 
5 namespace anima
6 {
7 
8 double
9 PochHammer(const double &x,
10  const unsigned int n)
11 {
12  double resVal = 1.0;
13 
14  for (unsigned int i = 0;i < n;++i)
15  resVal *= (x + i);
16 
17  return resVal;
18 }
19 
20 double
21 KummerMethod1(const double &x, const double &a, const double &b,
22  const unsigned int maxIter, const double tol)
23 {
24  double resVal = 1.0;
25 
26  bool stopLoop = false;
27  unsigned int counter = 2;
28 
29  std::vector <double> aVals(2);
30  aVals[0] = 1;
31  aVals[1] = 1.0 + x * a / b;
32 
33  while (counter < maxIter && !stopLoop)
34  {
35  double r = (a + counter - 1.0) / (counter * (b + counter - 1.0));
36  double newVal = aVals[1] + (aVals[1] - aVals[0]) * r * x;
37 
38  if ((counter != 2) && (std::abs(newVal - resVal) < tol * std::abs(resVal)))
39  stopLoop = true;
40  else
41  {
42  resVal = newVal;
43  aVals[0] = aVals[1];
44  aVals[1] = newVal;
45  }
46 
47  ++counter;
48  }
49 
50  return resVal;
51 }
52 
53 double
54 KummerMethod2(const double &x, const double &a, const double &b,
55  const unsigned int maxIter, const double tol)
56 {
57  double resVal = 1.0;
58 
59  bool stopLoop = false;
60  unsigned int counter = 0;
61  double factorial_counter = 1;
62 
63  while (counter < maxIter && !stopLoop)
64  {
65  ++counter;
66  factorial_counter *= counter;
67 
68  double tmpVal = resVal;
69 
70  double poch_a, poch_b;
71 
72  if (x > 0)
73  {
74  poch_a = PochHammer(1.0 - a,counter);
75  poch_b = PochHammer(b - a,counter);
76  }
77  else
78  {
79  poch_a = PochHammer(a,counter);
80  poch_b = PochHammer(1.0 + a - b,counter);
81  }
82 
83  resVal += poch_a * poch_b * std::pow(std::abs(x),-1.0 * counter) / factorial_counter;
84 
85  if ((counter != 1) && (std::abs(resVal - tmpVal) < tol * std::abs(tmpVal)))
86  stopLoop = true;
87  }
88 
89  if (x > 0)
90  resVal *= std::exp(x) * std::pow(x,(double)(a-b)) / std::tgamma(a);
91  else
92  resVal *= std::pow(-x,-1.0 * a) / std::tgamma(b-a);
93 
94  resVal *= std::tgamma(b);
95 
96  return resVal;
97 }
98 
99 double KummerIntegrandMethod(const double &x, const double &a, const double &b)
100 {
101  KummerIntegrand integrand;
102  integrand.SetXValue(x);
103  integrand.SetAValue(a);
104  integrand.SetBValue(b);
105  double resVal = boost::math::quadrature::gauss<double, 15>::integrate(integrand, 0.0, 1.0);
106  resVal *= std::tgamma(b) / std::tgamma(a) / std::tgamma(b - a);
107 
108  return resVal;
109 }
110 
111 double
112 GetKummerFunctionValue(const double &x, const double &a, const double &b,
113  const unsigned int maxIter, const double tol)
114 {
115  if ((a == 0) || (x == 0))
116  return 1.0;
117 
118  if (a == b)
119  return std::exp(x);
120 
121  if (a > 0 && b > a)
122  {
123  double resVal = KummerIntegrandMethod(x, a, b);
124 
125  if (x > 0)
126  resVal = std::exp(x + std::log(resVal));
127 
128  return resVal;
129  }
130 
131  double rFactor = std::abs(x * a / b);
132  if (rFactor < 20.0)
133  return KummerMethod1(x, a, b, maxIter, tol);
134  else
135  {
136  if (a > b)
137  {
138  double ap = b - a;
139  double xp = -x;
140  if (ap > b)
141  throw itk::ExceptionObject(__FILE__, __LINE__,"Invalid inputs for Kummer function using method 2",ITK_LOCATION);
142 
143  double tmpVal = KummerMethod2(xp,ap,b,maxIter,tol);
144  double logResVal = x + std::log(std::abs(tmpVal));
145  double factor = (0.0 < tmpVal) - (0.0 > tmpVal);
146  return factor * std::exp(logResVal);
147  }
148 
149  return KummerMethod2(x, a, b, maxIter, tol);
150  }
151 }
152 
153 double
154 GetScaledKummerFunctionValue(const double &x, const double &a, const double &b,
155  const unsigned int maxIter, const double tol)
156 {
157  if ((a == 0) || (x == 0))
158  return std::exp(-x);
159 
160  if (a == b)
161  return 1.0;
162 
163  if (a > 0 && b > a)
164  {
165  double resVal = KummerIntegrandMethod(x, a, b);
166 
167  if (x < 0)
168  resVal = std::exp(- x + std::log(resVal));
169 
170  return resVal;
171  }
172 
173  double rFactor = std::abs(x * a / b);
174  if (rFactor < 20.0)
175  return std::exp(-x + std::log(KummerMethod1(x, a, b, maxIter, tol)));
176  else
177  {
178  if (a > b)
179  {
180  double ap = b - a;
181  double xp = -x;
182  if (ap > b)
183  throw itk::ExceptionObject(__FILE__, __LINE__,"Invalid inputs for Kummer function using method 2",ITK_LOCATION);
184 
185  return KummerMethod2(xp, ap, b, maxIter, tol);
186  }
187 
188  return std::exp(-x + std::log(KummerMethod2(x, a, b, maxIter, tol)));
189  }
190 }
191 
192 } // end of namespace anima
double GetScaledKummerFunctionValue(const double &x, const double &a, const double &b, const unsigned int maxIter, const double tol)
Computes the confluent hypergeometric function 1F1 also known as the Kummer function M...
double KummerIntegrandMethod(const double &x, const double &a, const double &b)
According to Muller, K. E. (2001) ‘Computing the confluent hypergeometric function, M (a, b, x)’, Numerische Mathematik, pp. 179–196. Method with integral if b > a > 0.
double PochHammer(const double &x, const unsigned int n)
double KummerMethod1(const double &x, const double &a, const double &b, const unsigned int maxIter, const double tol)
According to Muller, K. E. (2001) ‘Computing the confluent hypergeometric function, M (a, b, x)’, Numerische Mathematik, pp. 179–196. Method 1.C, p.5.
double KummerMethod2(const double &x, const double &a, const double &b, const unsigned int maxIter, const double tol)
According to Muller, K. E. (2001) ‘Computing the confluent hypergeometric function, M (a, b, x)’, Numerische Mathematik, pp. 179–196. Method 2, p.6.
double GetKummerFunctionValue(const double &x, const double &a, const double &b, const unsigned int maxIter, const double tol)
Computes the confluent hypergeometric function 1F1 also known as the Kummer function M...