14#define DEFAULT_MAXEVALS 100
15#define DEFAULT_MAXPASSES 5
19#define RCDS_ABORT 0x0001UL
20static unsigned long rcdsFlags = 0;
31 rcdsFlags |= RCDS_ABORT;
33 fprintf(stderr,
"rcdsMin abort requested\n");
36 return rcdsFlags & RCDS_ABORT ? 1 : 0;
73void sort_two_arrays(
double *x,
double *y,
long n);
75void normalize_variables(
double *x0,
double *relative_x,
double *lowerLimit,
double *upperLimit,
long dimensions);
77void scale_variables(
double *x0,
double *relative_x,
double *lowerLimit,
double *upperLimit,
long dimensions);
80static long DIMENSIONS;
82long bracketmin(
double (*func)(
double *x,
long *invalid),
83 double *x0,
double f0,
double *dv,
double *lowerLimit,
double *upperLimit,
long dimensions,
double noise,
double step,
double *a10,
double *a20,
double **stepList,
double **flist,
long *nflist,
double *xm,
double *fm,
double *xmin,
double *fmin);
85long linescan(
double (*func)(
double *x,
long *invalid),
double *x0,
double f0,
double *dv,
double *lowerLimit,
double *upperLimit,
long dimensions,
double alo,
double ahi,
long Np,
double *step_list,
double *f_list,
long n_list,
double *xm,
double *fm,
double *xmin,
double *fmin);
87long outlier_1d(
double *x,
long n,
double mul_tol,
double perlim,
long *removed_index);
113long rcdsMin(
double *yReturn,
double *xBest,
double *xGuess,
double *dxGuess,
double *xLowerLimit,
double *xUpperLimit,
double **dmat0,
long dimensions,
double target,
115 double (*func)(
double *x,
long *invalid),
void (*report)(
double ymin,
double *xmin,
long pass,
long evals,
long dims),
long maxEvaluations,
117 double noise,
double rcdsStep,
unsigned long flags) {
118 long i, j, totalEvaluations = 0, inValid = 0, k, pass, Npmin = 6, direction;
120 double *dv = NULL, del = 0, f0, step = 0.01, f1, fm, ft, a1, a2, tmp, norm, maxp = 0, tmpf, *tmpx = NULL;
121 double *xm = NULL, *x1 = NULL, *xt = NULL, *ndv = NULL, *dotp = NULL, *x_value = NULL, *xmin = NULL, fmin;
122 double *step_list = NULL, *f_list = NULL, step_init;
126 if (rcdsStep > 0 && rcdsStep < 1)
131 DIMENSIONS = dimensions;
133 if (flags & SIMPLEX_VERBOSE_LEVEL1)
134 fprintf(stdout,
"rcdsMin dimensions: %ld\n", dimensions);
136 x0 = malloc(
sizeof(*x0) * dimensions);
137 tmpx = malloc(
sizeof(*tmpx) * dimensions);
139 normalize_variables(xGuess, x0, xLowerLimit, xUpperLimit, dimensions);
141 f0 = (*func)(xGuess, &inValid);
144 fprintf(stderr,
"error: initial guess is invalid in rcdsMin()\n");
151 dmat0 = malloc(
sizeof(*dmat0) * dimensions);
152 for (i = 0; i < dimensions; i++) {
153 dmat0[i] = calloc(dimensions,
sizeof(**dmat0));
154 for (j = 0; j < dimensions; j++)
161 for (i = 0; i < dimensions; i++) {
162 if (xLowerLimit && xUpperLimit) {
163 step += dxGuess[i] / (xUpperLimit[i] - xLowerLimit[i]);
170 if (rcdsStep > 0 && rcdsStep < 1)
173 xm = malloc(
sizeof(*xm) * dimensions);
174 xmin = malloc(
sizeof(*xmin) * dimensions);
175 memcpy(xm, x0,
sizeof(*xm) * dimensions);
176 memcpy(xmin, x0,
sizeof(*xm) * dimensions);
178 memcpy(xBest, xGuess,
sizeof(*xBest) * dimensions);
181 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
182 fprintf(stdout,
"rcdsMin: target value achieved in initial setup.\n");
185 (*report)(f0, xGuess, 0, 1, dimensions);
191 return (totalEvaluations);
195 maxPasses = DEFAULT_MAXPASSES;
197 x1 =
tmalloc(
sizeof(*x1) * dimensions);
198 xt =
tmalloc(
sizeof(*xt) * dimensions);
199 ndv =
tmalloc(
sizeof(*ndv) * dimensions);
200 dotp =
tmalloc(
sizeof(*dotp) * dimensions);
201 for (i = 0; i < dimensions; i++)
205 x_value =
tmalloc(
sizeof(*x_value) * dimensions);
207 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
208 fprintf(stdout,
"rcdsMin: starting conditions:\n");
209 for (direction = 0; direction < dimensions; direction++)
210 fprintf(stdout,
"direction %ld: guess=%le \n", direction, xGuess[direction]);
211 fprintf(stdout,
"starting funcation value %le \n", f0);
214 while (pass < maxPasses && !(rcdsFlags & RCDS_ABORT)) {
219 for (i = 0; !(rcdsFlags & RCDS_ABORT) && i < dimensions; i++) {
221 if (flags & SIMPLEX_VERBOSE_LEVEL1)
222 fprintf(stdout,
"begin iteration %ld, var %ld, nf=%ld\n", pass + 1, i + 1, totalEvaluations);
231 totalEvaluations += bracketmin(func, xm, fm, dv, xLowerLimit, xUpperLimit, dimensions, noise, step_init, &a1, &a2, &step_list, &f_list, &n_list, x1, &f1, xmin, &fmin);
232 memcpy(tmpx, x1,
sizeof(*tmpx) * dimensions);
234 if (flags & SIMPLEX_VERBOSE_LEVEL1)
235 fprintf(stdout,
"\niter %ld, dir (var) %ld: begin linescan %ld\n", pass + 1, i + 1, totalEvaluations);
236 if (rcdsFlags & RCDS_ABORT)
238 totalEvaluations += linescan(func, tmpx, tmpf, dv, xLowerLimit, xUpperLimit, dimensions, a1, a2, Npmin, step_list, f_list, n_list, x1, &f1, xmin, &fmin);
240 if ((fm - f1) > del) {
243 if (flags & SIMPLEX_VERBOSE_LEVEL1)
244 fprintf(stdout,
"iteration %ld, var %ld: del= %f updated", pass + 1, i + 1, del);
246 if (flags & SIMPLEX_VERBOSE_LEVEL1)
247 fprintf(stdout,
"iteration %ld, director %ld done, fm=%f, f1=%f\n", pass + 1, i + 1, fm, f1);
249 if (flags & RCDS_USE_MIN_FOR_BRACKET) {
251 memcpy(xm, xmin,
sizeof(*xm) * dimensions);
254 memcpy(xm, x1,
sizeof(*xm) * dimensions);
257 if (flags & SIMPLEX_VERBOSE_LEVEL1)
258 fprintf(stderr,
"\niteration %ld, fm=%f fmin=%f\n", pass + 1, fm, fmin);
259 if (rcdsFlags & RCDS_ABORT)
262 for (i = 0; i < dimensions; i++) {
263 xt[i] = 2 * xm[i] - x0[i];
264 if (fabs(xt[i]) > 1) {
270 scale_variables(x_value, xt, xLowerLimit, xUpperLimit, dimensions);
271 ft = (*func)(x_value, &inValid);
276 tmp = 2 * (f0 - 2 * fm + ft) * pow((f0 - fm - del) / (ft - f0), 2);
277 if ((f0 <= ft) || tmp >= del) {
278 if (flags & SIMPLEX_VERBOSE_LEVEL1)
279 fprintf(stdout,
"dir %ld not replaced, %d, %d\n", k, f0 <= ft, tmp >= del);
282 if (flags & SIMPLEX_VERBOSE_LEVEL1)
283 fprintf(stdout,
"compute dotp\n");
285 for (i = 0; i < dimensions; i++) {
286 norm += (xm[i] - x0[i]) * (xm[i] - x0[i]);
288 norm = pow(norm, 0.5);
289 for (i = 0; i < dimensions; i++)
290 ndv[i] = (xm[i] - x0[i]) / norm;
292 for (i = 0; i < dimensions; i++) {
295 for (j = 0; j < dimensions; j++)
296 dotp[i] += ndv[j] * dv[j];
297 dotp[i] = fabs(dotp[i]);
302 if (flags & SIMPLEX_VERBOSE_LEVEL1)
303 fprintf(stdout,
"max dot product <0.9, do bracketmin and linescan...\n");
304 if (k < dimensions - 1) {
305 for (i = k; i < dimensions - 1; i++) {
306 for (j = 0; j < dimensions; j++)
307 dmat0[i][j] = dmat0[i + 1][j];
310 for (j = 0; j < dimensions; j++)
311 dmat0[dimensions - 1][j] = ndv[j];
312 dv = dmat0[dimensions - 1];
313 totalEvaluations += bracketmin(func, xm, fm, dv, xLowerLimit, xUpperLimit, dimensions, noise, step, &a1, &a2, &step_list, &f_list, &n_list, x1, &f1, xmin, &fmin);
315 memcpy(tmpx, x1,
sizeof(*tmpx) * dimensions);
317 totalEvaluations += linescan(func, tmpx, tmpf, dv, xLowerLimit, xUpperLimit, dimensions, a1, a2, Npmin, step_list, f_list, n_list, x1, &f1, xmin, &fmin);
318 memcpy(xm, x1,
sizeof(*xm) * dimensions);
320 if (flags & SIMPLEX_VERBOSE_LEVEL1)
321 fprintf(stderr,
"fm=%le \n", fm);
323 if (flags & SIMPLEX_VERBOSE_LEVEL1)
324 fprintf(stdout,
" , skipped new direction %ld, max dot product %f\n", k, maxp);
328 if (totalEvaluations > maxEvaluations) {
329 fprintf(stderr,
"Terminated, reaching function evaluation limit %ld > %ld\n", totalEvaluations, maxEvaluations);
332 if (2.0 * fabs(f0 - fmin) < tolerance * (fabs(f0) + fabs(fmin)) && tolerance > 0) {
333 if (flags & SIMPLEX_VERBOSE_LEVEL1)
334 fprintf(stdout,
"Reach tolerance, terminated, f0=%le, fmin=%le, f0-fmin=%le\n", f0, fmin, f0 - fmin);
337 if (fmin <= target) {
338 if (flags & SIMPLEX_VERBOSE_LEVEL1)
339 fprintf(stdout,
"Reach target, terminated, fm=%le, target=%le\n", fm, target);
343 memcpy(x0, xm,
sizeof(*x0) * dimensions);
348 scale_variables(xBest, xmin, xLowerLimit, xUpperLimit, dimensions);
364 return (totalEvaluations);
387long bracketmin(
double (*func)(
double *x,
long *invalid),
388 double *x0,
double f0,
double *dv,
double *lowerLimit,
double *upperLimit,
long dimensions,
389 double noise,
double step,
double *a10,
double *a20,
double **stepList,
double **fList,
390 long *nflist,
double *xm,
double *fm,
double *xmin,
double *fmin) {
391 long nf = 0, inValid, i, n_list, count;
392 static double *x1 = NULL, *x2 = NULL, gold_r = 1.618034;
393 double *step_list = NULL, *f_list = NULL;
394 double f1, step_init, am, a1, a2, f2, tmp, step0;
395 static double *x_value = NULL;
398 memcpy(xm, x0,
sizeof(*xm) * dimensions);
402 x1 = malloc(
sizeof(*x1) * dimensions);
404 f_list = malloc(
sizeof(*f_list) * 100);
406 step_list = malloc(
sizeof(*step_list) * 100);
413 for (i = 0; i < dimensions; i++) {
414 x1[i] = x0[i] + dv[i] * step;
415 if (fabs(x1[i]) > 1) {
421 x_value = malloc(
sizeof(*x_value) * dimensions);
426 scale_variables(x_value, x1, lowerLimit, upperLimit, dimensions);
428 f1 = (*func)(x_value, &inValid);
435 step_list[n_list] = step;
440 memcpy(xm, x1,
sizeof(*xm) * dimensions);
445 memcpy(xmin, x1,
sizeof(*xmin) * dimensions);
448 while (f1 < *fm + noise * 3 && !(rcdsFlags & RCDS_ABORT)) {
451 if (fabs(step) < 0.1)
452 step = step * (1.0 + gold_r);
457 for (i = 0; i < dimensions; i++) {
458 x1[i] = x0[i] + dv[i] * step;
459 if (fabs(x1[i]) > 1) {
467 scale_variables(x_value, x1, lowerLimit, upperLimit, dimensions);
468 f1 = (*func)(x_value, &inValid);
474 f_list =
trealloc(f_list,
sizeof(*f_list) * (n_list + 1));
475 step_list =
trealloc(step_list,
sizeof(*step_list) * (n_list + 1));
482 step_list[n_list] = step;
487 memcpy(xm, x1,
sizeof(*xm) * dimensions);
491 memcpy(xmin, x1,
sizeof(*xmin) * dimensions);
496 if (f0 > *fm + noise * 3) {
500 for (i = 0; i < n_list; i++)
510 *stepList = step_list;
522 x2 = malloc(
sizeof(*x2) * dimensions);
524 step = -1 * step_init;
526 for (i = 0; i < dimensions; i++) {
527 x2[i] = x0[i] + dv[i] * step;
528 if (fabs(x2[i]) > 1) {
536 scale_variables(x_value, x2, lowerLimit, upperLimit, dimensions);
537 f2 = (*func)(x_value, &inValid);
543 f_list =
trealloc(f_list,
sizeof(*f_list) * (n_list + 1));
544 step_list =
trealloc(step_list,
sizeof(*step_list) * (n_list + 1));
547 step_list[n_list] = step;
553 memcpy(xm, x2,
sizeof(*xm) * dimensions);
557 memcpy(xmin, x2,
sizeof(*xmin) * dimensions);
560 while (f2 < *fm + noise * 3 && !(rcdsFlags & RCDS_ABORT)) {
562 if (fabs(step) < 0.1)
563 step = step * (1.0 + gold_r);
567 for (i = 0; i < dimensions; i++) {
568 x2[i] = x0[i] + dv[i] * step;
569 if (fabs(x2[i]) > 1) {
577 scale_variables(x_value, x2, lowerLimit, upperLimit, dimensions);
578 f2 = (*func)(x_value, &inValid);
590 f_list =
trealloc(f_list,
sizeof(*f_list) * (n_list + 1));
591 step_list =
trealloc(step_list,
sizeof(*step_list) * (n_list + 1));
594 step_list[n_list] = step;
600 memcpy(xm, x2,
sizeof(*xm) * dimensions);
604 memcpy(xmin, x2,
sizeof(*xmin) * dimensions);
616 for (i = 0; i < n_list; i++)
619 sort_two_arrays(step_list, f_list, n_list);
623 *stepList = step_list;
636void scale_variables(
double *x0,
double *relative_x,
double *lowerLimit,
double *upperLimit,
long dimensions) {
638 if (lowerLimit && upperLimit) {
639 for (i = 0; i < dimensions; i++) {
640 x0[i] = relative_x[i] * (upperLimit[i] - lowerLimit[i]) + lowerLimit[i];
643 memcpy(x0, relative_x,
sizeof(*x0) * dimensions);
647void normalize_variables(
double *x0,
double *relative_x,
double *lowerLimit,
double *upperLimit,
long dimensions) {
649 if (lowerLimit && upperLimit) {
650 for (i = 0; i < dimensions; i++) {
651 relative_x[i] = (x0[i] - lowerLimit[i]) / (upperLimit[i] - lowerLimit[i]);
654 memcpy(relative_x, x0,
sizeof(*relative_x) * dimensions);
677long linescan(
double (*func)(
double *x,
long *invalid),
double *x0,
double f0,
double *dv,
double *lowerLimit,
double *upperLimit,
long dimensions,
double alo,
double ahi,
long Np,
double *step_list,
double *f_list,
long n_list,
double *xm,
double *fm,
double *xmin,
double *fmin) {
678 long nf = 0, i, j, k, MP, n_new, terms, *order;
681 long *is_outlier, outliers;
682 double a1, f1, tmp_min, tmp_max, tmp, delta, delta2, mina;
683 static double *x1 = NULL, *aNew = NULL, *fNew = NULL, *av = NULL, *x_value = NULL;
684 double *coef, *coefSigma, chi, *diff, *tmpa = NULL, *tmpf = NULL, *fv = NULL;
687 fprintf(stderr,
"high bound should be larger than the low bound\n");
692 delta = (ahi - alo) / (Np - 1);
693 delta2 = delta / 2.0;
695 x1 = malloc(
sizeof(*x1) * dimensions);
699 aNew = malloc(
sizeof(*aNew) * Np);
701 fNew = malloc(
sizeof(*fNew) * Np);
703 x_value = malloc(
sizeof(*x_value) * dimensions);
705 for (i = 0; i < Np && !(rcdsFlags & RCDS_ABORT); i++) {
706 a1 = alo + delta * i;
707 mina = fabs(a1 - step_list[0]);
708 for (j = 1; j < n_list; j++) {
709 tmp = fabs(a1 - step_list[j]);
711 mina = fabs(a1 - step_list[j]);
716 if (mina + 1.0e-16 > delta2) {
717 for (k = 0; k < dimensions; k++) {
718 x1[k] = x0[k] + dv[k] * a1;
720 scale_variables(x_value, x1, lowerLimit, upperLimit, dimensions);
721 f1 = (*func)(x_value, &inValid);
725 memcpy(xmin, x1,
sizeof(*xmin) * dimensions);
736 if (rcdsFlags & RCDS_ABORT) {
745 if (n_new + n_list > 100) {
746 f_list =
trealloc(f_list,
sizeof(*f_list) * (n_list + n_new + 1));
747 step_list =
trealloc(step_list,
sizeof(*step_list) * (n_list + n_new + 1));
749 for (i = 0; i < n_new; i++) {
750 step_list[n_list + i] = aNew[i];
751 f_list[n_list + i] = fNew[i];
764 sort_two_arrays(step_list, f_list, n_list);
767 for (i = 0; i < dimensions; i++)
768 xm[i] = x0[i] + step_list[imin] * dv[i];
772 memcpy(xmin, xm,
sizeof(*xmin) * dimensions);
777 tmp_min = MAX(step_list[0], step_list[imin] - 6 * delta);
778 tmp_max = MIN(step_list[n_list - 1], step_list[imin] + 6 * delta);
782 av =
tmalloc(
sizeof(*av) * MP);
783 for (i = 0; i < MP; i++)
784 av[i] = tmp_min + (tmp_max - tmp_min) * i * 1.0 / MP;
785 fv =
tmalloc(
sizeof(*fv) * MP);
789 coef =
tmalloc(
sizeof(*coef) * terms);
790 coefSigma =
tmalloc(
sizeof(*coefSigma) * terms);
791 order =
tmalloc(
sizeof(*order) * terms);
792 for (i = 0; i < terms; i++)
794 diff =
tmalloc(
sizeof(*diff) * n_list);
796 lsfp(step_list, f_list, NULL, n_list, terms, order, coef, coefSigma, &chi, diff);
799 is_outlier =
tmalloc(
sizeof(*is_outlier) * n_list);
800 for (i = 0; i < n_list; i++)
801 diff[i] = -1.0 * diff[i];
803 outliers = outlier_1d(diff, n_list, 3.0, 0.25, is_outlier);
805 for (i = 0; i < n_list; i++) {
806 diff[i] = -1 * diff[i];
810 tmpa =
tmalloc(
sizeof(*tmpa) * n_list);
811 tmpf =
tmalloc(
sizeof(*tmpf) * n_list);
813 for (j = 0; j < n_list; j++)
814 if (!is_outlier[j]) {
815 tmpa[n_new] = step_list[j];
816 tmpf[n_new] = f_list[j];
820 lsfp(tmpa, tmpf, NULL, n_new, terms, order, coef, coefSigma, &chi, diff);
825 for (i = 0; i < MP; i++) {
826 fv[i] = coef[0] + av[i] * coef[1] + coef[2] * av[i] * av[i];
829 for (i = 0; i < dimensions; i++) {
830 x1[i] = xm[i] = x0[i] + av[imin] * dv[i];
832 scale_variables(x_value, x1, lowerLimit, upperLimit, dimensions);
833 memcpy(xm, x1,
sizeof(*xm) * dimensions);
835 f1 = (*func)(x_value, &inValid);
842 memcpy(xmin, x1,
sizeof(*xmin) * dimensions);
867void sort_two_arrays(
double *x,
double *y,
long n) {
871 tmpx = malloc(
sizeof(*tmpx) * n);
872 memcpy(tmpx, x,
sizeof(*tmpx) * n);
873 tmpy = malloc(
sizeof(*tmpy) * n);
876 for (i = 0; i < n; i++) {
877 for (j = 0; j < n; j++) {
883 for (i = 0; i < n; i++) {
908long outlier_1d(
double *x,
long n,
double mul_tol,
double perlim,
long *is_outlier) {
909 long i, j, outlier = 0, *index = NULL, upl, dnl, upcut, dncut;
910 double *tmpx = NULL, *diff = NULL, ave1 = 0, ave2 = 0;
914 index =
tmalloc(
sizeof(*index) * n);
915 tmpx =
tmalloc(
sizeof(*tmpx) * n);
916 diff =
tmalloc(
sizeof(*diff) * n);
919 memcpy(tmpx, x,
sizeof(*tmpx) * n);
922 for (i = 0; i < n; i++) {
924 for (j = 0; j < n; j++) {
932 for (i = 1; i < n; i++) {
933 diff[i - 1] = tmpx[i] - tmpx[i - 1];
938 for (i = 0; i < n - 2; i++)
940 for (i = 1; i < n - 1; i++)
944 if (diff[n - 2] > mul_tol * ave1) {
945 is_outlier[index[n - 2]] = 1;
948 if (diff[0] > mul_tol * ave2) {
949 is_outlier[index[0]] = 1;
954 upl = MAX((
int)(n * (1 - perlim)), 3) - 1;
955 dnl = MAX((
int)(n * perlim), 2) - 1;
957 for (i = dnl; i <= upl; i++)
959 ave1 /= upl - dnl + 1;
964 for (i = upl; i < n - 1; i++) {
965 if (diff[i] > mul_tol * ave1) {
970 for (i = dnl; i >= 0; i--) {
971 if (diff[i] > mul_tol * ave1) {
975 for (i = upcut; i < n; i++) {
976 is_outlier[index[i]] = 1;
979 for (i = dncut; i >= 0; i--) {
980 is_outlier[index[i]] = 1;
void * trealloc(void *old_ptr, uint64_t size_of_block)
Reallocates a memory block to a new size.
int free_zarray_2d(void **array, uint64_t n1, uint64_t n2)
Frees a 2D array and its associated memory.
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
int index_min_max(int64_t *imin, int64_t *imax, double *list, int64_t n)
Finds the indices of the minimum and maximum values in a list of doubles.
long rcdsMin(double *yReturn, double *xBest, double *xGuess, double *dxGuess, double *xLowerLimit, double *xUpperLimit, double **dmat0, long dimensions, double target, double tolerance, double(*func)(double *x, long *invalid), void(*report)(double ymin, double *xmin, long pass, long evals, long dims), long maxEvaluations, long maxPasses, double noise, double rcdsStep, unsigned long flags)
Performs minimization using the RCDS (Robust Conjugate Direction Search) algorithm.
long rcdsMinAbort(long abort)
Sets or queries the abort flag for the RCDS minimization.
int double_cmpasc(const void *a, const void *b)
Compare two doubles in ascending order.