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);
113long rcdsMin(
double *yReturn,
double *xBest,
double *xGuess,
double *dxGuess,
double *xLowerLimit,
double *xUpperLimit,
double **dmat0,
long dimensions,
double target, {
…}
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;
393 static double *x1 = NULL, *x2 = NULL, gold_r = 1.618034;
394 double *step_list = NULL, *f_list = NULL;
395 double f1, step_init, am, a1, a2, f2, tmp, step0;
396 static double *x_value = NULL;
399 memcpy(xm, x0,
sizeof(*xm) * dimensions);
403 x1 = malloc(
sizeof(*x1) * dimensions);
405 f_list = malloc(
sizeof(*f_list) * 100);
407 step_list = malloc(
sizeof(*step_list) * 100);
414 for (i = 0; i < dimensions; i++) {
415 x1[i] = x0[i] + dv[i] * step;
416 if (fabs(x1[i]) > 1) {
422 x_value = malloc(
sizeof(*x_value) * dimensions);
427 scale_variables(x_value, x1, lowerLimit, upperLimit, dimensions);
429 f1 = (*func)(x_value, &inValid);
436 step_list[n_list] = step;
441 memcpy(xm, x1,
sizeof(*xm) * dimensions);
446 memcpy(xmin, x1,
sizeof(*xmin) * dimensions);
449 while (f1 < *fm + noise * 3 && !(rcdsFlags & RCDS_ABORT)) {
452 if (fabs(step) < 0.1)
453 step = step * (1.0 + gold_r);
458 for (i = 0; i < dimensions; i++) {
459 x1[i] = x0[i] + dv[i] * step;
460 if (fabs(x1[i]) > 1) {
468 scale_variables(x_value, x1, lowerLimit, upperLimit, dimensions);
469 f1 = (*func)(x_value, &inValid);
475 f_list =
trealloc(f_list,
sizeof(*f_list) * (n_list + 1));
476 step_list =
trealloc(step_list,
sizeof(*step_list) * (n_list + 1));
483 step_list[n_list] = step;
488 memcpy(xm, x1,
sizeof(*xm) * dimensions);
492 memcpy(xmin, x1,
sizeof(*xmin) * dimensions);
497 if (f0 > *fm + noise * 3) {
501 for (i = 0; i < n_list; i++)
511 *stepList = step_list;
523 x2 = malloc(
sizeof(*x2) * dimensions);
525 step = -1 * step_init;
527 for (i = 0; i < dimensions; i++) {
528 x2[i] = x0[i] + dv[i] * step;
529 if (fabs(x2[i]) > 1) {
537 scale_variables(x_value, x2, lowerLimit, upperLimit, dimensions);
538 f2 = (*func)(x_value, &inValid);
544 f_list =
trealloc(f_list,
sizeof(*f_list) * (n_list + 1));
545 step_list =
trealloc(step_list,
sizeof(*step_list) * (n_list + 1));
548 step_list[n_list] = step;
554 memcpy(xm, x2,
sizeof(*xm) * dimensions);
558 memcpy(xmin, x2,
sizeof(*xmin) * dimensions);
561 while (f2 < *fm + noise * 3 && !(rcdsFlags & RCDS_ABORT)) {
563 if (fabs(step) < 0.1)
564 step = step * (1.0 + gold_r);
568 for (i = 0; i < dimensions; i++) {
569 x2[i] = x0[i] + dv[i] * step;
570 if (fabs(x2[i]) > 1) {
578 scale_variables(x_value, x2, lowerLimit, upperLimit, dimensions);
579 f2 = (*func)(x_value, &inValid);
591 f_list =
trealloc(f_list,
sizeof(*f_list) * (n_list + 1));
592 step_list =
trealloc(step_list,
sizeof(*step_list) * (n_list + 1));
595 step_list[n_list] = step;
601 memcpy(xm, x2,
sizeof(*xm) * dimensions);
605 memcpy(xmin, x2,
sizeof(*xmin) * dimensions);
617 for (i = 0; i < n_list; i++)
620 sort_two_arrays(step_list, f_list, n_list);
624 *stepList = step_list;
637void scale_variables(
double *x0,
double *relative_x,
double *lowerLimit,
double *upperLimit,
long dimensions) {
639 if (lowerLimit && upperLimit) {
640 for (i = 0; i < dimensions; i++) {
641 x0[i] = relative_x[i] * (upperLimit[i] - lowerLimit[i]) + lowerLimit[i];
644 memcpy(x0, relative_x,
sizeof(*x0) * dimensions);
648void normalize_variables(
double *x0,
double *relative_x,
double *lowerLimit,
double *upperLimit,
long dimensions) {
650 if (lowerLimit && upperLimit) {
651 for (i = 0; i < dimensions; i++) {
652 relative_x[i] = (x0[i] - lowerLimit[i]) / (upperLimit[i] - lowerLimit[i]);
655 memcpy(relative_x, x0,
sizeof(*relative_x) * dimensions);
678long 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) {
679 long nf = 0, i, j, k, MP, n_new, terms, *order;
682 long *is_outlier, outliers;
683 double a1, f1, tmp_min, tmp_max, tmp, delta, delta2, mina;
684 static double *x1 = NULL, *aNew = NULL, *fNew = NULL, *av = NULL, *x_value = NULL;
685 double *coef, *coefSigma, chi, *diff, *tmpa = NULL, *tmpf = NULL, *fv = NULL;
688 fprintf(stderr,
"high bound should be larger than the low bound\n");
693 delta = (ahi - alo) / (Np - 1);
694 delta2 = delta / 2.0;
696 x1 = malloc(
sizeof(*x1) * dimensions);
700 aNew = malloc(
sizeof(*aNew) * Np);
702 fNew = malloc(
sizeof(*fNew) * Np);
704 x_value = malloc(
sizeof(*x_value) * dimensions);
706 for (i = 0; i < Np && !(rcdsFlags & RCDS_ABORT); i++) {
707 a1 = alo + delta * i;
708 mina = fabs(a1 - step_list[0]);
709 for (j = 1; j < n_list; j++) {
710 tmp = fabs(a1 - step_list[j]);
712 mina = fabs(a1 - step_list[j]);
717 if (mina + 1.0e-16 > delta2) {
718 for (k = 0; k < dimensions; k++) {
719 x1[k] = x0[k] + dv[k] * a1;
721 scale_variables(x_value, x1, lowerLimit, upperLimit, dimensions);
722 f1 = (*func)(x_value, &inValid);
726 memcpy(xmin, x1,
sizeof(*xmin) * dimensions);
737 if (rcdsFlags & RCDS_ABORT) {
746 if (n_new + n_list > 100) {
747 f_list =
trealloc(f_list,
sizeof(*f_list) * (n_list + n_new + 1));
748 step_list =
trealloc(step_list,
sizeof(*step_list) * (n_list + n_new + 1));
750 for (i = 0; i < n_new; i++) {
751 step_list[n_list + i] = aNew[i];
752 f_list[n_list + i] = fNew[i];
765 sort_two_arrays(step_list, f_list, n_list);
768 for (i = 0; i < dimensions; i++)
769 xm[i] = x0[i] + step_list[imin] * dv[i];
773 memcpy(xmin, xm,
sizeof(*xmin) * dimensions);
778 tmp_min = MAX(step_list[0], step_list[imin] - 6 * delta);
779 tmp_max = MIN(step_list[n_list - 1], step_list[imin] + 6 * delta);
783 av =
tmalloc(
sizeof(*av) * MP);
784 for (i = 0; i < MP; i++)
785 av[i] = tmp_min + (tmp_max - tmp_min) * i * 1.0 / MP;
786 fv =
tmalloc(
sizeof(*fv) * MP);
790 coef =
tmalloc(
sizeof(*coef) * terms);
791 coefSigma =
tmalloc(
sizeof(*coefSigma) * terms);
792 order =
tmalloc(
sizeof(*order) * terms);
793 for (i = 0; i < terms; i++)
795 diff =
tmalloc(
sizeof(*diff) * n_list);
797 lsfp(step_list, f_list, NULL, n_list, terms, order, coef, coefSigma, &chi, diff);
800 is_outlier =
tmalloc(
sizeof(*is_outlier) * n_list);
801 for (i = 0; i < n_list; i++)
802 diff[i] = -1.0 * diff[i];
804 outliers = outlier_1d(diff, n_list, 3.0, 0.25, is_outlier);
806 for (i = 0; i < n_list; i++) {
807 diff[i] = -1 * diff[i];
811 tmpa =
tmalloc(
sizeof(*tmpa) * n_list);
812 tmpf =
tmalloc(
sizeof(*tmpf) * n_list);
814 for (j = 0; j < n_list; j++)
815 if (!is_outlier[j]) {
816 tmpa[n_new] = step_list[j];
817 tmpf[n_new] = f_list[j];
821 lsfp(tmpa, tmpf, NULL, n_new, terms, order, coef, coefSigma, &chi, diff);
826 for (i = 0; i < MP; i++) {
827 fv[i] = coef[0] + av[i] * coef[1] + coef[2] * av[i] * av[i];
830 for (i = 0; i < dimensions; i++) {
831 x1[i] = xm[i] = x0[i] + av[imin] * dv[i];
833 scale_variables(x_value, x1, lowerLimit, upperLimit, dimensions);
834 memcpy(xm, x1,
sizeof(*xm) * dimensions);
836 f1 = (*func)(x_value, &inValid);
843 memcpy(xmin, x1,
sizeof(*xmin) * dimensions);
868void sort_two_arrays(
double *x,
double *y,
long n) {
872 tmpx = malloc(
sizeof(*tmpx) * n);
873 memcpy(tmpx, x,
sizeof(*tmpx) * n);
874 tmpy = malloc(
sizeof(*tmpy) * n);
877 for (i = 0; i < n; i++) {
878 for (j = 0; j < n; j++) {
884 for (i = 0; i < n; i++) {
909long outlier_1d(
double *x,
long n,
double mul_tol,
double perlim,
long *is_outlier) {
910 long i, j, outlier = 0, *index = NULL, upl, dnl, upcut, dncut;
911 double *tmpx = NULL, *diff = NULL, ave1 = 0, ave2 = 0;
915 index =
tmalloc(
sizeof(*index) * n);
916 tmpx =
tmalloc(
sizeof(*tmpx) * n);
917 diff =
tmalloc(
sizeof(*diff) * n);
920 memcpy(tmpx, x,
sizeof(*tmpx) * n);
923 for (i = 0; i < n; i++) {
925 for (j = 0; j < n; j++) {
933 for (i = 1; i < n; i++) {
934 diff[i - 1] = tmpx[i] - tmpx[i - 1];
939 for (i = 0; i < n - 2; i++)
941 for (i = 1; i < n - 1; i++)
945 if (diff[n - 2] > mul_tol * ave1) {
946 is_outlier[index[n - 2]] = 1;
949 if (diff[0] > mul_tol * ave2) {
950 is_outlier[index[0]] = 1;
955 upl = MAX((
int)(n * (1 - perlim)), 3) - 1;
956 dnl = MAX((
int)(n * perlim), 2) - 1;
958 for (i = dnl; i <= upl; i++)
960 ave1 /= upl - dnl + 1;
965 for (i = upl; i < n - 1; i++) {
966 if (diff[i] > mul_tol * ave1) {
971 for (i = dnl; i >= 0; i--) {
972 if (diff[i] > mul_tol * ave1) {
976 for (i = upcut; i < n; i++) {
977 is_outlier[index[i]] = 1;
980 for (i = dncut; i >= 0; i--) {
981 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.