1 /* Copyright (C) 2007 Christian Holm Christensen <cholm@nbi.dk>
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 2.1 of
6 * the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 #include <flow/AliFMDFlowEfficiency.h>
22 T sign(const T& x, const T& y)
24 return (y >= 0 ? fabs(x) : -fabs(x));
27 //____________________________________________________________________
29 AliFMDFlowEfficiency::LnGamma(Double_t z)
32 Double_t c[] = { 2.5066282746310005, 76.18009172947146,
33 -86.50532032941677, 24.01409824083091,
34 -1.231739572450155, 0.1208650973866179e-2,
39 t = (x+.5 * log(t) - t);
40 Double_t s = 1.000000000190015;
41 for (UInt_t i = 1; i < 7; i++) {
45 Double_t v = t + log(c[0]*s/x);
49 //____________________________________________________________________
51 AliFMDFlowEfficiency::BetaCf(Double_t x, Double_t a, Double_t b)
53 Int_t itmax = 500; // Maximum # of iterations
54 Double_t eps = 3e-14; // Precision.
55 Double_t fpmin = 1e-30;
61 Double_t d = 1 - qab * x / qap;
62 if (fabs(d) < fpmin) d = fpmin;
66 for (m = 1; m <= itmax; m++) {
68 Double_t aa = m * (b - m) * x / ((qam + m2) * (a + m2));
70 if (fabs(d) < fpmin) d = fpmin;
72 if (fabs(c) < fpmin) d = fpmin;
75 aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
77 if (fabs(d) < fpmin) d = fpmin;
79 if (fabs(c) < fpmin) d = fpmin;
83 if (fabs(dd - 1) <= eps) break;
86 std::cerr << "a or b too big, or max # iterations too small"
94 //____________________________________________________________________
96 AliFMDFlowEfficiency::IBetaI(Double_t a, Double_t b, Double_t x)
100 std::cerr << "x not in [0,1]" << std::endl;
103 if (x == 0 || x == 1) bt = 0;
105 bt = (exp(LnGamma(a + b) - LnGamma(a) - LnGamma(b)
106 + a * log(x) + b * log(1 - x)));
107 if (x < (a + 1) / (a + b + 2))
108 return bt * BetaCf(x, a, b) / a;
109 return 1 - bt * BetaCf(1-x, b, a)/ b;
112 //____________________________________________________________________
114 AliFMDFlowEfficiency::BetaAB(Double_t a, Double_t b, Int_t k, Int_t n)
116 if (a == b) return 0;
118 Int_t c2 = n - k + 1;
119 return IBetaI(c1, c2, b) - IBetaI(c1, c2, a);
122 //____________________________________________________________________
124 AliFMDFlowEfficiency::SearchUpper(Double_t low, Int_t k, Int_t n, Double_t c)
126 Double_t integral = BetaAB(low, 1, k, n);
127 if (integral == c) return 1; // lucky -- this is the solution
128 if (integral < c) return -1;// no solution exists
129 Double_t tooHigh = 1; // upper edge estimate
130 Double_t tooLow = low;
133 // Use a bracket-and-bisect search. Loop 20 times, to end up with a
134 // root guaranteed accurate to better than 0.1%.
135 for (UInt_t i = 0; i < 20; i++) {
136 test = 0.5 * (tooLow + tooHigh);
137 integral = BetaAB(low, test, k, n);
138 if (integral > c) tooHigh = test;
143 //____________________________________________________________________
145 AliFMDFlowEfficiency::SearchLower(Double_t high, Int_t k, Int_t n, Double_t c)
147 Double_t integral = BetaAB(0, high, k, n);
148 if (integral == c) return 0; // lucky -- this is the solution
149 if (integral < c) return -1;// no solution exists
150 Double_t tooLow = 0; // lower edge estimate
151 Double_t tooHigh = high;
154 // Use a bracket-and-bisect search. Loop 20 times, to end up with a
155 // root guaranteed accurate to better than 0.1%.
156 for (UInt_t i = 0; i < 20; i++) {
157 test = 0.5 * (tooHigh + tooLow);
158 integral = BetaAB(test, high, k, n);
159 if (integral > c) tooLow = test;
165 //____________________________________________________________________
167 AliFMDFlowEfficiency::Brent(Double_t ax, Double_t bx, Double_t cx,
168 Double_t& xmin, Int_t k, Int_t n, Double_t c,
171 const Int_t kItMax = 100;
172 const Double_t kGold = 0.3819660;
173 const Double_t kEps = 1e-10;
176 Double_t a = (ax < cx ? ax : cx);
177 Double_t b = (ax > cx ? ax : cx);
183 Double_t fw = Length(x, k, n, c);
187 for (iter = 1; iter <= kItMax; iter++) {
188 Double_t xm = .5 * (a + b);
189 Double_t tol1 = tol * fabs(x) + kEps;
190 Double_t tol2 = 2 * tol1;
191 if (fabs(x - xm) < (tol2 - .5 * (b-a))) {
195 if (fabs(e) > tol1) {
196 Double_t r = (x - w) * (fx - fv);
197 Double_t q = (x - v) * (fx - fw);
198 Double_t p = (x - v) * q - (x - w) * r;
204 if (fabs(p) >= fabs(.5 * q * t) ||
207 e = (x > xm ? a - x : b - x);
213 if (u - a < tol2 || b - u < tol2)
214 d = sign(tol1, xm - x);
218 e = (x >= xm ? a - x : b - x);
221 Double_t u = (fabs(d) >= tol1 ? x + d : x + sign(tol1, d));
222 Double_t fu = Length(u, k, n, c);
236 if (fu <= fw || w == x) {
242 else if (fu <= fv || v == x || v == w) {
248 std::cerr << "Brett: too many iterations" << std::endl;
253 //____________________________________________________________________
255 AliFMDFlowEfficiency::Length(Double_t l, Int_t k, Int_t n, Double_t c)
257 Double_t h = SearchUpper(l, k, n, c);
258 if (h == -1) return 2;
262 //____________________________________________________________________
264 AliFMDFlowEfficiency::Interval(Int_t k, Int_t n,
265 Double_t& low, Double_t& high,
274 Double_t e = Double_t(k) / n;
279 h = SearchUpper(l, k, n, c);
283 l = SearchLower(h, k, n, c);
286 Brent(0, .5, 1, l, n, k, 1e-9, c);
287 h = l + Length(l, n, k, c);
294 //____________________________________________________________________