6 /******************************
7 *** Non-linear programming ***
8 ******************************/
10 /* Hooke-Jeeves algorithm for nonlinear minimization
12 Based on the pseudocodes by Bell and Pike (CACM 9(9):684-685), and
13 the revision by Tomlin and Smith (CACM 12(11):637-638). Both of the
14 papers are comments on Kaupe's Algorithm 178 "Direct Search" (ACM
15 6(6):313-314). The original algorithm was designed by Hooke and
16 Jeeves (ACM 8:212-229). This program is further revised according to
17 Johnson's implementation at Netlib (opt/hooke.c).
19 Hooke-Jeeves algorithm is very simple and it works quite well on a
20 few examples. However, it might fail to converge due to its heuristic
21 nature. A possible improvement, as is suggested by Johnson, may be to
22 choose a small r at the beginning to quickly approach to the minimum
23 and a large r at later step to hit the minimum.
26 static double __kmin_hj_aux(kmin_f func
, int n
, double *x1
, void *data
, double fx1
, double *dx
, int *n_calls
)
30 for (k
= 0; k
!= n
; ++k
) {
32 ftmp
= func(n
, x1
, data
); ++j
;
33 if (ftmp
< fx1
) fx1
= ftmp
;
34 else { /* search the opposite direction */
36 x1
[k
] += dx
[k
] + dx
[k
];
37 ftmp
= func(n
, x1
, data
); ++j
;
38 if (ftmp
< fx1
) fx1
= ftmp
;
39 else x1
[k
] -= dx
[k
]; /* back to the original x[k] */
43 return fx1
; /* here: fx1=f(n,x1) */
46 double kmin_hj(kmin_f func
, int n
, double *x
, void *data
, double r
, double eps
, int max_calls
)
48 double fx
, fx1
, *x1
, *dx
, radius
;
50 x1
= (double*)calloc(n
, sizeof(double));
51 dx
= (double*)calloc(n
, sizeof(double));
52 for (k
= 0; k
!= n
; ++k
) { /* initial directions, based on MGJ */
53 dx
[k
] = fabs(x
[k
]) * r
;
54 if (dx
[k
] == 0) dx
[k
] = r
;
57 fx1
= fx
= func(n
, x
, data
); ++n_calls
;
59 memcpy(x1
, x
, n
* sizeof(double)); /* x1 = x */
60 fx1
= __kmin_hj_aux(func
, n
, x1
, data
, fx
, dx
, &n_calls
);
62 for (k
= 0; k
!= n
; ++k
) {
64 dx
[k
] = x1
[k
] > x
[k
]? fabs(dx
[k
]) : 0.0 - fabs(dx
[k
]);
66 x1
[k
] = x1
[k
] + x1
[k
] - t
;
69 if (n_calls
>= max_calls
) break;
70 fx1
= func(n
, x1
, data
); ++n_calls
;
71 fx1
= __kmin_hj_aux(func
, n
, x1
, data
, fx1
, dx
, &n_calls
);
73 for (k
= 0; k
!= n
; ++k
)
74 if (fabs(x1
[k
] - x
[k
]) > .5 * fabs(dx
[k
])) break;
78 if (n_calls
>= max_calls
) break;
80 for (k
= 0; k
!= n
; ++k
) dx
[k
] *= r
;
81 } else break; /* converge */
87 // I copied this function somewhere several years ago with some of my modifications, but I forgot the source.
88 double kmin_brent(kmin1_f func
, double a
, double b
, void *data
, double tol
, double *xmin
)
90 double bound
, u
, r
, q
, fu
, tmp
, fa
, fb
, fc
, c
;
91 const double gold1
= 1.6180339887;
92 const double gold2
= 0.3819660113;
93 const double tiny
= 1e-20;
94 const int max_iter
= 100;
96 double e
, d
, w
, v
, mid
, tol1
, tol2
, p
, eold
, fv
, fw
;
99 fa
= func(a
, data
); fb
= func(b
, data
);
100 if (fb
> fa
) { // swap, such that f(a) > f(b)
101 tmp
= a
; a
= b
; b
= tmp
;
102 tmp
= fa
; fa
= fb
; fb
= tmp
;
104 c
= b
+ gold1
* (b
- a
), fc
= func(c
, data
); // golden section extrapolation
106 bound
= b
+ 100.0 * (c
- b
); // the farthest point where we want to go
107 r
= (b
- a
) * (fb
- fc
);
108 q
= (b
- c
) * (fb
- fa
);
109 if (fabs(q
- r
) < tiny
) { // avoid 0 denominator
110 tmp
= q
> r
? tiny
: 0.0 - tiny
;
112 u
= b
- ((b
- c
) * q
- (b
- a
) * r
) / (2.0 * tmp
); // u is the parabolic extrapolation point
113 if ((b
> u
&& u
> c
) || (b
< u
&& u
< c
)) { // u lies between b and c
115 if (fu
< fc
) { // (b,u,c) bracket the minimum
116 a
= b
; b
= u
; fa
= fb
; fb
= fu
;
118 } else if (fu
> fb
) { // (a,b,u) bracket the minimum
122 u
= c
+ gold1
* (c
- b
); fu
= func(u
, data
); // golden section extrapolation
123 } else if ((c
> u
&& u
> bound
) || (c
< u
&& u
< bound
)) { // u lies between c and bound
125 if (fu
< fc
) { // fb > fc > fu
126 b
= c
; c
= u
; u
= c
+ gold1
* (c
- b
);
127 fb
= fc
; fc
= fu
; fu
= func(u
, data
);
128 } else { // (b,c,u) bracket the minimum
130 fa
= fb
; fb
= fc
; fc
= fu
;
133 } else if ((u
> bound
&& bound
> c
) || (u
< bound
&& bound
< c
)) { // u goes beyond the bound
134 u
= bound
; fu
= func(u
, data
);
135 } else { // u goes the other way around, use golden section extrapolation
136 u
= c
+ gold1
* (c
- b
); fu
= func(u
, data
);
139 fa
= fb
; fb
= fc
; fc
= fu
;
141 if (a
> c
) u
= a
, a
= c
, c
= u
; // swap
143 // now, a<b<c, fa>fb and fb<fc, move on to Brent's algorithm
145 w
= v
= b
; fv
= fw
= fb
;
146 for (iter
= 0; iter
!= max_iter
; ++iter
) {
148 tol2
= 2.0 * (tol1
= tol
* fabs(b
) + tiny
);
149 if (fabs(b
- mid
) <= (tol2
- 0.5 * (c
- a
))) {
150 *xmin
= b
; return fb
; // found
152 if (fabs(e
) > tol1
) {
153 // related to parabolic interpolation
154 r
= (b
- w
) * (fb
- fv
);
155 q
= (b
- v
) * (fb
- fw
);
156 p
= (b
- v
) * q
- (b
- w
) * r
;
158 if (q
> 0.0) p
= 0.0 - p
;
161 if (fabs(p
) >= fabs(0.5 * q
* eold
) || p
<= q
* (a
- b
) || p
>= q
* (c
- b
)) {
162 d
= gold2
* (e
= (b
>= mid
? a
- b
: c
- b
));
164 d
= p
/ q
; u
= b
+ d
; // actual parabolic interpolation happens here
165 if (u
- a
< tol2
|| c
- u
< tol2
)
166 d
= (mid
> b
)? tol1
: 0.0 - tol1
;
168 } else d
= gold2
* (e
= (b
>= mid
? a
- b
: c
- b
)); // golden section interpolation
169 u
= fabs(d
) >= tol1
? b
+ d
: b
+ (d
> 0.0? tol1
: -tol1
);
171 if (fu
<= fb
) { // u is the minimum point so far
174 v
= w
; w
= b
; b
= u
; fv
= fw
; fw
= fb
; fb
= fu
;
175 } else { // adjust (a,c) and (u,v,w)
178 if (fu
<= fw
|| w
== b
) {
181 } else if (fu
<= fv
|| v
== b
|| v
== w
) {
190 static inline float SIGN(float a
, float b
)
192 return b
>= 0 ? (a
>= 0 ? a
: -a
) : (a
>= 0 ? -a
: a
);
195 double krf_brent(double x1
, double x2
, double tol
, double (*func
)(double, void*), void *data
, int *err
)
197 const int max_iter
= 100;
198 const double eps
= 3e-8f
;
200 double a
= x1
, b
= x2
, c
= x2
, d
, e
, min1
, min2
;
201 double fa
, fb
, fc
, p
, q
, r
, s
, tol1
, xm
;
204 fa
= func(a
, data
), fb
= func(b
, data
);
205 if ((fa
> 0.0f
&& fb
> 0.0f
) || (fa
< 0.0f
&& fb
< 0.0f
)) {
210 for (i
= 0; i
< max_iter
; ++i
) {
211 if ((fb
> 0.0f
&& fc
> 0.0f
) || (fb
< 0.0f
&& fc
< 0.0f
)) {
216 if (fabs(fc
) < fabs(fb
)) {
218 fa
= fb
, fb
= fc
, fc
= fa
;
220 tol1
= 2.0f
* eps
* fabs(b
) + 0.5f
* tol
;
222 if (fabs(xm
) <= tol1
|| fb
== 0.0f
)
224 if (fabs(e
) >= tol1
&& fabs(fa
) > fabs(fb
)) {
232 p
= s
* (2.0f
* xm
* q
* (q
- r
) - (b
- a
) * (r
- 1.0f
));
233 q
= (q
- 1.0f
) * (r
- 1.0f
) * (s
- 1.0f
);
235 if (p
> 0.0f
) q
= -q
;
237 min1
= 3.0f
* xm
* q
- fabs(tol1
* q
);
239 if (2.0f
* p
< (min1
< min2
? min1
: min2
)) {
252 if (fabs(d
) > tol1
) b
+= d
;
253 else b
+= SIGN(tol1
, xm
);
260 /*************************
261 *** Special functions ***
262 *************************/
264 /* Log gamma function
266 * AS245, 2nd algorithm, http://lib.stat.cmu.edu/apstat/245
268 double kf_lgamma(double z
)
271 x
+= 0.1659470187408462e-06 / (z
+7);
272 x
+= 0.9934937113930748e-05 / (z
+6);
273 x
-= 0.1385710331296526 / (z
+5);
274 x
+= 12.50734324009056 / (z
+4);
275 x
-= 176.6150291498386 / (z
+3);
276 x
+= 771.3234287757674 / (z
+2);
277 x
-= 1259.139216722289 / (z
+1);
278 x
+= 676.5203681218835 / z
;
279 x
+= 0.9999999999995183;
280 return log(x
) - 5.58106146679532777 - z
+ (z
-0.5) * log(z
+6.5);
283 /* complementary error function
284 * \frac{2}{\sqrt{\pi}} \int_x^{\infty} e^{-t^2} dt
285 * AS66, 2nd algorithm, http://lib.stat.cmu.edu/apstat/66
287 double kf_erfc(double x
)
289 const double p0
= 220.2068679123761;
290 const double p1
= 221.2135961699311;
291 const double p2
= 112.0792914978709;
292 const double p3
= 33.912866078383;
293 const double p4
= 6.37396220353165;
294 const double p5
= .7003830644436881;
295 const double p6
= .03526249659989109;
296 const double q0
= 440.4137358247522;
297 const double q1
= 793.8265125199484;
298 const double q2
= 637.3336333788311;
299 const double q3
= 296.5642487796737;
300 const double q4
= 86.78073220294608;
301 const double q5
= 16.06417757920695;
302 const double q6
= 1.755667163182642;
303 const double q7
= .08838834764831844;
305 z
= fabs(x
) * M_SQRT2
;
306 if (z
> 37.) return x
> 0.? 0. : 2.;
307 expntl
= exp(z
* z
* - .5);
308 if (z
< 10. / M_SQRT2
) // for small z
309 p
= expntl
* ((((((p6
* z
+ p5
) * z
+ p4
) * z
+ p3
) * z
+ p2
) * z
+ p1
) * z
+ p0
)
310 / (((((((q7
* z
+ q6
) * z
+ q5
) * z
+ q4
) * z
+ q3
) * z
+ q2
) * z
+ q1
) * z
+ q0
);
311 else p
= expntl
/ 2.506628274631001 / (z
+ 1. / (z
+ 2. / (z
+ 3. / (z
+ 4. / (z
+ .65)))));
312 return x
> 0.? 2. * p
: 2. * (1. - p
);
315 /* The following computes regularized incomplete gamma functions.
316 * Formulas are taken from Wiki, with additional input from Numerical
317 * Recipes in C (for modified Lentz's algorithm) and AS245
318 * (http://lib.stat.cmu.edu/apstat/245).
320 * A good online calculator is available at:
322 * http://www.danielsoper.com/statcalc/calc23.aspx
324 * It calculates upper incomplete gamma function, which equals
325 * kf_gammaq(s,z)*tgamma(s).
328 #define KF_GAMMA_EPS 1e-14
329 #define KF_TINY 1e-290
331 // regularized lower incomplete gamma function, by series expansion
332 static double _kf_gammap(double s
, double z
)
336 for (k
= 1, sum
= x
= 1.; k
< 100; ++k
) {
337 sum
+= (x
*= z
/ (s
+ k
));
338 if (x
/ sum
< KF_GAMMA_EPS
) break;
340 return exp(s
* log(z
) - z
- kf_lgamma(s
+ 1.) + log(sum
));
342 // regularized upper incomplete gamma function, by continued fraction
343 static double _kf_gammaq(double s
, double z
)
347 f
= 1. + z
- s
; C
= f
; D
= 0.;
348 // Modified Lentz's algorithm for computing continued fraction
349 // See Numerical Recipes in C, 2nd edition, section 5.2
350 for (j
= 1; j
< 100; ++j
) {
351 double a
= j
* (s
- j
), b
= (j
<<1) + 1 + z
- s
, d
;
353 if (D
< KF_TINY
) D
= KF_TINY
;
355 if (C
< KF_TINY
) C
= KF_TINY
;
359 if (fabs(d
- 1.) < KF_GAMMA_EPS
) break;
361 return exp(s
* log(z
) - z
- kf_lgamma(s
) - log(f
));
364 double kf_gammap(double s
, double z
)
366 return z
<= 1. || z
< s
? _kf_gammap(s
, z
) : 1. - _kf_gammaq(s
, z
);
369 double kf_gammaq(double s
, double z
)
371 return z
<= 1. || z
< s
? 1. - _kf_gammap(s
, z
) : _kf_gammaq(s
, z
);
374 /* Regularized incomplete beta function. The method is taken from
375 * Numerical Recipe in C, 2nd edition, section 6.4. The following web
376 * page calculates the incomplete beta function, which equals
377 * kf_betai(a,b,x) * gamma(a) * gamma(b) / gamma(a+b):
379 * http://www.danielsoper.com/statcalc/calc36.aspx
381 static double kf_betai_aux(double a
, double b
, double x
)
385 if (x
== 0.) return 0.;
386 if (x
== 1.) return 1.;
387 f
= 1.; C
= f
; D
= 0.;
388 // Modified Lentz's algorithm for computing continued fraction
389 for (j
= 1; j
< 200; ++j
) {
392 aa
= (j
&1)? -(a
+ m
) * (a
+ b
+ m
) * x
/ ((a
+ 2*m
) * (a
+ 2*m
+ 1))
393 : m
* (b
- m
) * x
/ ((a
+ 2*m
- 1) * (a
+ 2*m
));
395 if (D
< KF_TINY
) D
= KF_TINY
;
397 if (C
< KF_TINY
) C
= KF_TINY
;
401 if (fabs(d
- 1.) < KF_GAMMA_EPS
) break;
403 return exp(kf_lgamma(a
+b
) - kf_lgamma(a
) - kf_lgamma(b
) + a
* log(x
) + b
* log(1.-x
)) / a
/ f
;
405 double kf_betai(double a
, double b
, double x
)
407 return x
< (a
+ 1.) / (a
+ b
+ 2.)? kf_betai_aux(a
, b
, x
) : 1. - kf_betai_aux(b
, a
, 1. - x
);
414 double km_ks_dist(int na
, const double a
[], int nb
, const double b
[]) // a[] and b[] MUST BE sorted
417 double fa
= 0, fb
= 0, sup
= 0, na1
= 1. / na
, nb1
= 1. / nb
;
418 while (ia
< na
|| ib
< nb
) {
419 if (ia
== na
) fb
+= nb1
, ++ib
;
420 else if (ib
== nb
) fa
+= na1
, ++ia
;
421 else if (a
[ia
] < b
[ib
]) fa
+= na1
, ++ia
;
422 else if (a
[ia
] > b
[ib
]) fb
+= nb1
, ++ib
;
423 else fa
+= na1
, fb
+= nb1
, ++ia
, ++ib
;
424 if (sup
< fabs(fa
- fb
)) sup
= fabs(fa
- fb
);
432 KSORT_INIT_GENERIC(double)
433 int main(int argc
, char *argv
[])
435 double x
= 5.5, y
= 3;
437 double xx
[] = {0.22, -0.87, -2.39, -1.79, 0.37, -1.54, 1.28, -0.31, -0.74, 1.72, 0.38, -0.17, -0.62, -1.10, 0.30, 0.15, 2.30, 0.19, -0.50, -0.09};
438 double yy
[] = {-5.13, -2.19, -2.43, -3.83, 0.50, -3.25, 4.32, 1.63, 5.18, -0.43, 7.11, 4.87, -3.10, -5.81, 3.76, 6.31, 2.58, 0.07, 5.76, 3.50};
439 ks_introsort(double, 20, xx
); ks_introsort(double, 20, yy
);
440 printf("K-S distance: %f\n", km_ks_dist(20, xx
, 20, yy
));
441 printf("erfc(%lg): %lg, %lg\n", x
, erfc(x
), kf_erfc(x
));
442 printf("upper-gamma(%lg,%lg): %lg\n", x
, y
, kf_gammaq(y
, x
)*tgamma(y
));
443 a
= 2; b
= 2; x
= 0.5;
444 printf("incomplete-beta(%lg,%lg,%lg): %lg\n", a
, b
, x
, kf_betai(a
, b
, x
) / exp(kf_lgamma(a
+b
) - kf_lgamma(a
) - kf_lgamma(b
)));