SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
rcds_powell.c File Reference

Detailed Description

Implementation of the RCDS (Robust Conjugate Direction Search) algorithm.

This code is translated from XiaoBiao Huang's MATLAB code for the RCDS algorithm. The RCDS algorithm is used for automated tuning via minimization.

Reference: X. Huang, et al. Nucl. Instr. Methods, A, 726 (2013) 77-83.

Definition in file rcds_powell.c.

#include "mdb.h"
#include <time.h>

Go to the source code of this file.

Functions

long rcdsMinAbort (long abort)
 Sets or queries the abort flag for the RCDS minimization.
 
void sort_two_arrays (double *x, double *y, long n)
 
void normalize_variables (double *x0, double *relative_x, double *lowerLimit, double *upperLimit, long dimensions)
 
void scale_variables (double *x0, double *relative_x, double *lowerLimit, double *upperLimit, long dimensions)
 
long bracketmin (double(*func)(double *x, long *invalid), 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)
 
long 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)
 
long outlier_1d (double *x, long n, double mul_tol, double perlim, long *removed_index)
 
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.
 

Function Documentation

◆ bracketmin()

long bracketmin ( double(* func )(double *x, long *invalid),
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 )

Definition at line 387 of file rcds_powell.c.

390 {
391 long nf = 0, inValid, i, n_list;
392 //long count;
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;
397
398 *fm = f0;
399 memcpy(xm, x0, sizeof(*xm) * dimensions);
400 am = 0;
401
402 if (!x1)
403 x1 = malloc(sizeof(*x1) * dimensions);
404 if (!f_list)
405 f_list = malloc(sizeof(*f_list) * 100);
406 if (!step_list)
407 step_list = malloc(sizeof(*step_list) * 100);
408 n_list = 0;
409 step_list[0] = 0;
410 f_list[0] = f0;
411 n_list++;
412 step_init = step;
413 inValid = 0;
414 for (i = 0; i < dimensions; i++) {
415 x1[i] = x0[i] + dv[i] * step;
416 if (fabs(x1[i]) > 1) {
417 inValid = 1;
418 break;
419 }
420 }
421 if (!x_value)
422 x_value = malloc(sizeof(*x_value) * dimensions);
423
424 if (inValid)
425 f1 = DBL_MAX;
426 else {
427 scale_variables(x_value, x1, lowerLimit, upperLimit, dimensions);
428 /*need scale variable values before calling the function */
429 f1 = (*func)(x_value, &inValid);
430 nf++;
431 if (inValid)
432 f1 = DBL_MAX;
433 }
434
435 f_list[n_list] = f1;
436 step_list[n_list] = step;
437 n_list++;
438
439 if (f1 < *fm) {
440 *fm = f1;
441 memcpy(xm, x1, sizeof(*xm) * dimensions);
442 am = step;
443 }
444 if (f1 < *fmin) {
445 *fmin = f1;
446 memcpy(xmin, x1, sizeof(*xmin) * dimensions);
447 }
448 //count = 0;
449 while (f1 < *fm + noise * 3 && !(rcdsFlags & RCDS_ABORT)) {
450 step0 = step;
451 /*maximum step 0.1 */
452 if (fabs(step) < 0.1)
453 step = step * (1.0 + gold_r);
454 else
455 step = step + 0.01;
456
457 inValid = 0;
458 for (i = 0; i < dimensions; i++) {
459 x1[i] = x0[i] + dv[i] * step;
460 if (fabs(x1[i]) > 1) {
461 inValid = 1;
462 break;
463 }
464 }
465 if (inValid) {
466 f1 = DBL_MAX;
467 } else {
468 scale_variables(x_value, x1, lowerLimit, upperLimit, dimensions);
469 f1 = (*func)(x_value, &inValid);
470 if (inValid)
471 f1 = DBL_MAX;
472 nf++;
473 }
474 if (n_list > 100) {
475 f_list = trealloc(f_list, sizeof(*f_list) * (n_list + 1));
476 step_list = trealloc(step_list, sizeof(*step_list) * (n_list + 1));
477 }
478 if (inValid) {
479 step = step0; /*get the last vaild solution */
480 break;
481 }
482 f_list[n_list] = f1;
483 step_list[n_list] = step;
484 n_list++;
485 if (f1 < *fm) {
486 *fm = f1;
487 am = step;
488 memcpy(xm, x1, sizeof(*xm) * dimensions);
489 }
490 if (f1 < *fmin) {
491 *fmin = f1;
492 memcpy(xmin, x1, sizeof(*xmin) * dimensions);
493 }
494 //count++;
495 }
496 a2 = step;
497 if (f0 > *fm + noise * 3) {
498 a1 = 0;
499 a1 = a1 - am;
500 a2 = a2 - am;
501 for (i = 0; i < n_list; i++)
502 step_list[i] -= am;
503 free(x1);
504 x1 = NULL;
505 free(x2);
506 x2 = NULL;
507 *a10 = a1;
508 *a20 = a2;
509
510 *fList = f_list;
511 *stepList = step_list;
512 *nflist = n_list;
513 *a10 = a1;
514 *a20 = a2;
515 free(x1);
516 x1 = NULL;
517 free(x2);
518 x2 = NULL;
519 return nf;
520 }
521
522 if (!x2)
523 x2 = malloc(sizeof(*x2) * dimensions);
524 /*go to negative direction */
525 step = -1 * step_init;
526 inValid = 0;
527 for (i = 0; i < dimensions; i++) {
528 x2[i] = x0[i] + dv[i] * step;
529 if (fabs(x2[i]) > 1) {
530 inValid = 1;
531 break;
532 }
533 }
534 if (inValid)
535 f2 = DBL_MAX;
536 else {
537 scale_variables(x_value, x2, lowerLimit, upperLimit, dimensions);
538 f2 = (*func)(x_value, &inValid);
539 if (inValid)
540 f2 = DBL_MAX;
541 nf++;
542 }
543 if (n_list > 100) {
544 f_list = trealloc(f_list, sizeof(*f_list) * (n_list + 1));
545 step_list = trealloc(step_list, sizeof(*step_list) * (n_list + 1));
546 }
547 f_list[n_list] = f2;
548 step_list[n_list] = step;
549 n_list++;
550
551 if (f2 < *fm) {
552 *fm = f2;
553 am = step;
554 memcpy(xm, x2, sizeof(*xm) * dimensions);
555 }
556 if (f2 < *fmin) {
557 *fmin = f2;
558 memcpy(xmin, x2, sizeof(*xmin) * dimensions);
559 }
560 //count = 0;
561 while (f2 < *fm + noise * 3 && !(rcdsFlags & RCDS_ABORT)) {
562 step0 = step;
563 if (fabs(step) < 0.1)
564 step = step * (1.0 + gold_r);
565 else
566 step = step - 0.01;
567 inValid = 0;
568 for (i = 0; i < dimensions; i++) {
569 x2[i] = x0[i] + dv[i] * step;
570 if (fabs(x2[i]) > 1) {
571 inValid = 1;
572 break;
573 }
574 }
575 if (inValid) {
576 f2 = DBL_MAX;
577 } else {
578 scale_variables(x_value, x2, lowerLimit, upperLimit, dimensions);
579 f2 = (*func)(x_value, &inValid);
580 if (inValid)
581 f2 = DBL_MAX;
582 nf++;
583 }
584 if (inValid) {
585 /* get the last valid solution */
586 step = step0;
587 break;
588 }
589
590 if (n_list > 100) {
591 f_list = trealloc(f_list, sizeof(*f_list) * (n_list + 1));
592 step_list = trealloc(step_list, sizeof(*step_list) * (n_list + 1));
593 }
594 f_list[n_list] = f2;
595 step_list[n_list] = step;
596 n_list++;
597 //count++;
598 if (f2 < *fm) {
599 *fm = f2;
600 am = step;
601 memcpy(xm, x2, sizeof(*xm) * dimensions);
602 }
603 if (f2 < *fmin) {
604 *fmin = f2;
605 memcpy(xmin, x2, sizeof(*xmin) * dimensions);
606 }
607 }
608
609 a1 = step;
610 if (a1 > a2) {
611 tmp = a1;
612 a1 = a2;
613 a2 = tmp;
614 }
615 a1 = a1 - am;
616 a2 = a2 - am;
617 for (i = 0; i < n_list; i++)
618 step_list[i] -= am;
619
620 sort_two_arrays(step_list, f_list, n_list);
621 /******/
622 /*move linescan here instead of powellMain so that no need to return step_list and f_list */
623
624 *stepList = step_list;
625 *fList = f_list;
626 *nflist = n_list;
627
628 free(x1);
629 x1 = NULL;
630 free(x2);
631 x2 = NULL;
632 *a10 = a1;
633 *a20 = a2;
634 return nf;
635}
void * trealloc(void *old_ptr, uint64_t size_of_block)
Reallocates a memory block to a new size.
Definition array.c:181

◆ linescan()

long 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 )

Definition at line 678 of file rcds_powell.c.

678 {
679 long nf = 0, i, j, k, MP, n_new, terms, *order;
680 long inValid;
681 int64_t imin, imax;
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;
686
687 if (alo >= ahi) {
688 fprintf(stderr, "high bound should be larger than the low bound\n");
689 return 0;
690 }
691 if (Np < 6)
692 Np = 6;
693 delta = (ahi - alo) / (Np - 1);
694 delta2 = delta / 2.0;
695 if (!x1)
696 x1 = malloc(sizeof(*x1) * dimensions);
697 /*add interpolation points to eveanly space */
698 n_new = 0;
699 if (!aNew)
700 aNew = malloc(sizeof(*aNew) * Np);
701 if (!fNew)
702 fNew = malloc(sizeof(*fNew) * Np);
703 if (!x_value)
704 x_value = malloc(sizeof(*x_value) * dimensions);
705
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]);
711 if (tmp < mina) {
712 mina = fabs(a1 - step_list[j]);
713 }
714 }
715 /*remove points which mian<=delta/2.0, keep the insert points if mina>delta/2.0 */
716 /*added a small value 1.0e-16, to keep the point that close to delta/2.0 */
717 if (mina + 1.0e-16 > delta2) {
718 for (k = 0; k < dimensions; k++) {
719 x1[k] = x0[k] + dv[k] * a1;
720 }
721 scale_variables(x_value, x1, lowerLimit, upperLimit, dimensions);
722 f1 = (*func)(x_value, &inValid);
723 nf++;
724 if (f1 < *fmin) {
725 *fmin = f1;
726 memcpy(xmin, x1, sizeof(*xmin) * dimensions);
727 }
728 if (inValid) {
729 f1 = DBL_MAX;
730 } else {
731 aNew[n_new] = a1;
732 fNew[n_new] = f1;
733 n_new++;
734 }
735 }
736 }
737 if (rcdsFlags & RCDS_ABORT) {
738 if (x1)
739 free(x1);
740 x1 = NULL;
741 return nf;
742 }
743
744 if (n_new) {
745 /*merge insertion points */
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));
749 }
750 for (i = 0; i < n_new; i++) {
751 step_list[n_list + i] = aNew[i];
752 f_list[n_list + i] = fNew[i];
753 }
754 n_list += n_new;
755 }
756
757 if (aNew)
758 free(aNew);
759 aNew = NULL;
760 if (fNew)
761 free(fNew);
762 fNew = NULL;
763
764 /*sort new list after adding inserting points */
765 sort_two_arrays(step_list, f_list, n_list);
766
767 index_min_max(&imin, &imax, f_list, n_list);
768 for (i = 0; i < dimensions; i++)
769 xm[i] = x0[i] + step_list[imin] * dv[i];
770 *fm = f_list[imin];
771 if (*fm < *fmin) {
772 *fmin = *fm;
773 memcpy(xmin, xm, sizeof(*xmin) * dimensions);
774 }
775 if (n_list <= 5)
776 return nf;
777 /*else, do outlier */
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);
780
781 MP = 101;
782 if (!av)
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);
787
788 /* polynormial fit */
789 terms = 3;
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++)
794 order[i] = i;
795 diff = tmalloc(sizeof(*diff) * n_list);
796
797 lsfp(step_list, f_list, NULL, n_list, terms, order, coef, coefSigma, &chi, diff);
798
799 /*do outlier based on 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];
803
804 outliers = outlier_1d(diff, n_list, 3.0, 0.25, is_outlier);
805
806 for (i = 0; i < n_list; i++) {
807 diff[i] = -1 * diff[i];
808 }
809 if (outliers <= 1) {
810 if (outliers == 1) {
811 tmpa = tmalloc(sizeof(*tmpa) * n_list);
812 tmpf = tmalloc(sizeof(*tmpf) * n_list);
813 n_new = 0;
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];
818 n_new++;
819 }
820
821 lsfp(tmpa, tmpf, NULL, n_new, terms, order, coef, coefSigma, &chi, diff);
822
823 free(tmpf);
824 free(tmpa);
825 }
826 for (i = 0; i < MP; i++) {
827 fv[i] = coef[0] + av[i] * coef[1] + coef[2] * av[i] * av[i];
828 }
829 index_min_max(&imin, &imax, fv, MP);
830 for (i = 0; i < dimensions; i++) {
831 x1[i] = xm[i] = x0[i] + av[imin] * dv[i];
832 }
833 scale_variables(x_value, x1, lowerLimit, upperLimit, dimensions);
834 memcpy(xm, x1, sizeof(*xm) * dimensions);
835
836 f1 = (*func)(x_value, &inValid);
837 nf++;
838 if (inValid)
839 f1 = DBL_MAX;
840 *fm = f1;
841 if (f1 < *fmin) {
842 *fmin = f1;
843 memcpy(xmin, x1, sizeof(*xmin) * dimensions);
844 }
845 } else {
846 /* do nothing, use the minimum result */
847 }
848 if (x1)
849 free(x1);
850 x1 = NULL;
851 free(av);
852 av = NULL;
853 free(coef);
854 coef = NULL;
855 free(coefSigma);
856 coefSigma = NULL;
857 free(order);
858 order = NULL;
859 free(diff);
860 diff = NULL;
861 free(is_outlier);
862 is_outlier = NULL;
863 free(fv);
864 fv = NULL;
865 return nf;
866}
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:59
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.
Definition findMinMax.c:116

◆ normalize_variables()

void normalize_variables ( double * x0,
double * relative_x,
double * lowerLimit,
double * upperLimit,
long dimensions )

Definition at line 648 of file rcds_powell.c.

648 {
649 long i;
650 if (lowerLimit && upperLimit) {
651 for (i = 0; i < dimensions; i++) {
652 relative_x[i] = (x0[i] - lowerLimit[i]) / (upperLimit[i] - lowerLimit[i]);
653 }
654 } else
655 memcpy(relative_x, x0, sizeof(*relative_x) * dimensions);
656}

◆ outlier_1d()

long outlier_1d ( double * x,
long n,
double mul_tol,
double perlim,
long * removed_index )

Definition at line 909 of file rcds_powell.c.

909 {
910 long i, j, outlier = 0, *index = NULL, upl, dnl, upcut, dncut;
911 double *tmpx = NULL, *diff = NULL, ave1 = 0, ave2 = 0;
912
913 if (n < 3)
914 return 0;
915 index = tmalloc(sizeof(*index) * n);
916 tmpx = tmalloc(sizeof(*tmpx) * n);
917 diff = tmalloc(sizeof(*diff) * n);
918
919 /*sort data x */
920 memcpy(tmpx, x, sizeof(*tmpx) * n);
921 qsort((void *)tmpx, n, sizeof(*tmpx), double_cmpasc);
922
923 for (i = 0; i < n; i++) {
924 is_outlier[i] = 0;
925 for (j = 0; j < n; j++) {
926 if (tmpx[i] == x[j])
927 break;
928 }
929 index[i] = j;
930 }
931
932 /*length of diff is n-1 */
933 for (i = 1; i < n; i++) {
934 diff[i - 1] = tmpx[i] - tmpx[i - 1];
935 }
936 if (n <= 4) {
937 /*n=3 or n=4; remove lower or upper diff; diff dimension is n-1 */
938 /*average from 0 to n-3 */
939 for (i = 0; i < n - 2; i++)
940 ave1 += diff[i];
941 for (i = 1; i < n - 1; i++)
942 ave2 += diff[i];
943 ave1 /= n - 2;
944 ave2 /= n - 2;
945 if (diff[n - 2] > mul_tol * ave1) {
946 is_outlier[index[n - 2]] = 1;
947 outlier++;
948 }
949 if (diff[0] > mul_tol * ave2) {
950 is_outlier[index[0]] = 1;
951 outlier++;
952 }
953 return outlier;
954 }
955 upl = MAX((int)(n * (1 - perlim)), 3) - 1;
956 dnl = MAX((int)(n * perlim), 2) - 1;
957 ave1 = 0;
958 for (i = dnl; i <= upl; i++)
959 ave1 += diff[i];
960 ave1 /= upl - dnl + 1;
961 upcut = n;
962 dncut = -1;
963
964 outlier = 0;
965 for (i = upl; i < n - 1; i++) {
966 if (diff[i] > mul_tol * ave1) {
967 upcut = i + 1;
968 }
969 }
970
971 for (i = dnl; i >= 0; i--) {
972 if (diff[i] > mul_tol * ave1) {
973 dncut = i;
974 }
975 }
976 for (i = upcut; i < n; i++) {
977 is_outlier[index[i]] = 1;
978 outlier++;
979 }
980 for (i = dncut; i >= 0; i--) {
981 is_outlier[index[i]] = 1;
982 outlier++;
983 }
984 free(tmpx);
985 free(diff);
986 free(index);
987 return outlier;
988}
int double_cmpasc(const void *a, const void *b)
Compare two doubles in ascending order.

◆ rcdsMin()

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.

This function minimizes the given objective function using the RCDS algorithm, which is based on Powell's method with line scans.

Parameters
yReturnPointer to store the best function value found.
xBestPointer to an array to store the best solution found.
xGuessInitial guess for the solution (array of size 'dimensions').
dxGuessInitial step sizes for each variable (array of size 'dimensions').
xLowerLimitLower bounds for the variables (array of size 'dimensions'). Can be NULL.
xUpperLimitUpper bounds for the variables (array of size 'dimensions'). Can be NULL.
dmat0Initial direction set (array of pointers to arrays of size 'dimensions x dimensions'). If NULL, unit vectors are used.
dimensionsNumber of variables (dimensions of the problem).
targetTarget function value to reach. The minimization will stop if this value is reached.
toleranceTolerance for termination condition. If negative, interpreted as fractional tolerance; if positive, interpreted as absolute tolerance.
funcObjective function to minimize. Should take an array of variables and a pointer to an invalid flag, and return the function value.
reportOptional reporting function to call after each iteration. Can be NULL.
maxEvaluationsMaximum number of function evaluations allowed.
maxPassesMaximum number of iterations (passes) allowed.
noiseEstimated noise level in the function value.
rcdsStepInitial step size for the line searches.
flagsControl flags for the algorithm behavior.
Returns
Number of function evaluations performed, or negative value on error.

Definition at line 113 of file rcds_powell.c.

117 {
118 long i, j, totalEvaluations = 0, inValid = 0, k, pass, Npmin = 6, direction;
119 double *x0 = NULL; /*normalized xGuess */
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;
123 long n_list;
124
125 rcdsFlags = 0;
126 if (rcdsStep > 0 && rcdsStep < 1)
127 step = rcdsStep;
128
129 if (dimensions <= 0)
130 return (-3);
131 DIMENSIONS = dimensions;
132
133 if (flags & SIMPLEX_VERBOSE_LEVEL1)
134 fprintf(stdout, "rcdsMin dimensions: %ld\n", dimensions);
135
136 x0 = malloc(sizeof(*x0) * dimensions);
137 tmpx = malloc(sizeof(*tmpx) * dimensions);
138 /*normalize xGuess to between 0 and 1; for step unification purpose */
139 normalize_variables(xGuess, x0, xLowerLimit, xUpperLimit, dimensions);
140
141 f0 = (*func)(xGuess, &inValid); /*note that the function evaluation still uses non-normalized */
142 if (inValid) {
143 f0 = DBL_MAX;
144 fprintf(stderr, "error: initial guess is invalid in rcdsMin()\n");
145 free(x0);
146 free(tmpx);
147 return (-3);
148 }
149 totalEvaluations++;
150 if (!dmat0) {
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++)
155 if (j == i)
156 dmat0[i][j] = 1;
157 }
158 }
159 if (dxGuess) {
160 step = 0;
161 for (i = 0; i < dimensions; i++) {
162 if (xLowerLimit && xUpperLimit) {
163 step += dxGuess[i] / (xUpperLimit[i] - xLowerLimit[i]);
164 } else
165 step += dxGuess[i];
166 }
167 step /= dimensions;
168 }
169 /* step = 0.01; */
170 if (rcdsStep > 0 && rcdsStep < 1)
171 step = rcdsStep;
172 /*best solution so far */
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);
177 fmin = fm = f0;
178 memcpy(xBest, xGuess, sizeof(*xBest) * dimensions);
179 *yReturn = f0;
180 if (f0 <= target) {
181 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
182 fprintf(stdout, "rcdsMin: target value achieved in initial setup.\n");
183 }
184 if (report)
185 (*report)(f0, xGuess, 0, 1, dimensions);
186 free(tmpx);
187 free(x0);
188 free(xm);
189 free(xmin);
190 free_zarray_2d((void **)dmat0, dimensions, dimensions);
191 return (totalEvaluations);
192 }
193
194 if (maxPasses <= 0)
195 maxPasses = DEFAULT_MAXPASSES;
196
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++)
202 dotp[i] = 0;
203
204 if (!x_value)
205 x_value = tmalloc(sizeof(*x_value) * dimensions);
206
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);
212 }
213 pass = 0;
214 while (pass < maxPasses && !(rcdsFlags & RCDS_ABORT)) {
215 step = step / 1.2;
216 step_init = step;
217 k = 0;
218 del = 0;
219 for (i = 0; !(rcdsFlags & RCDS_ABORT) && i < dimensions; i++) {
220 dv = dmat0[i];
221 if (flags & SIMPLEX_VERBOSE_LEVEL1)
222 fprintf(stdout, "begin iteration %ld, var %ld, nf=%ld\n", pass + 1, i + 1, totalEvaluations);
223 if (step_list) {
224 free(step_list);
225 step_list = NULL;
226 }
227 if (f_list) {
228 free(f_list);
229 f_list = NULL;
230 }
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);
233 tmpf = f1;
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)
237 break;
238 totalEvaluations += linescan(func, tmpx, tmpf, dv, xLowerLimit, xUpperLimit, dimensions, a1, a2, Npmin, step_list, f_list, n_list, x1, &f1, xmin, &fmin);
239 /*direction with largest decrease */
240 if ((fm - f1) > del) {
241 del = fm - f1;
242 k = i;
243 if (flags & SIMPLEX_VERBOSE_LEVEL1)
244 fprintf(stdout, "iteration %ld, var %ld: del= %f updated", pass + 1, i + 1, del);
245 }
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);
248
249 if (flags & RCDS_USE_MIN_FOR_BRACKET) {
250 fm = fmin;
251 memcpy(xm, xmin, sizeof(*xm) * dimensions);
252 } else {
253 fm = f1;
254 memcpy(xm, x1, sizeof(*xm) * dimensions);
255 }
256 }
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)
260 break;
261 inValid = 0;
262 for (i = 0; i < dimensions; i++) {
263 xt[i] = 2 * xm[i] - x0[i];
264 if (fabs(xt[i]) > 1) {
265 inValid = 1;
266 break;
267 }
268 }
269 if (!inValid) {
270 scale_variables(x_value, xt, xLowerLimit, xUpperLimit, dimensions);
271 ft = (*func)(x_value, &inValid);
272 totalEvaluations++;
273 }
274 if (inValid)
275 ft = DBL_MAX;
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);
280 } else {
281 /*compute norm of xm - x0 */
282 if (flags & SIMPLEX_VERBOSE_LEVEL1)
283 fprintf(stdout, "compute dotp\n");
284 norm = 0;
285 for (i = 0; i < dimensions; i++) {
286 norm += (xm[i] - x0[i]) * (xm[i] - x0[i]);
287 }
288 norm = pow(norm, 0.5);
289 for (i = 0; i < dimensions; i++)
290 ndv[i] = (xm[i] - x0[i]) / norm;
291 maxp = 0;
292 for (i = 0; i < dimensions; i++) {
293 dv = dmat0[i];
294 dotp[i] = 0;
295 for (j = 0; j < dimensions; j++)
296 dotp[i] += ndv[j] * dv[j];
297 dotp[i] = fabs(dotp[i]);
298 if (dotp[i] > maxp)
299 maxp = dotp[i];
300 }
301 if (maxp < 0.9) {
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];
308 }
309 }
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);
314
315 memcpy(tmpx, x1, sizeof(*tmpx) * dimensions);
316 tmpf = f1;
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);
319 fm = f1;
320 if (flags & SIMPLEX_VERBOSE_LEVEL1)
321 fprintf(stderr, "fm=%le \n", fm);
322 } else {
323 if (flags & SIMPLEX_VERBOSE_LEVEL1)
324 fprintf(stdout, " , skipped new direction %ld, max dot product %f\n", k, maxp);
325 }
326 }
327 /*termination */
328 if (totalEvaluations > maxEvaluations) {
329 fprintf(stderr, "Terminated, reaching function evaluation limit %ld > %ld\n", totalEvaluations, maxEvaluations);
330 break;
331 }
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);
335 break;
336 }
337 if (fmin <= target) {
338 if (flags & SIMPLEX_VERBOSE_LEVEL1)
339 fprintf(stdout, "Reach target, terminated, fm=%le, target=%le\n", fm, target);
340 break;
341 }
342 f0 = fm;
343 memcpy(x0, xm, sizeof(*x0) * dimensions);
344 pass++;
345 }
346
347 /*x1, f1 best solution */
348 scale_variables(xBest, xmin, xLowerLimit, xUpperLimit, dimensions);
349 *yReturn = fmin;
350
351 free(x0);
352 free(xm);
353 free_zarray_2d((void **)dmat0, dimensions, dimensions);
354 free(x1);
355 free(xt);
356 free(ndv);
357 free(dotp);
358 free(f_list);
359 f_list = NULL;
360 free(step_list);
361 step_list = NULL;
362 free(tmpx);
363 free(x_value);
364 return (totalEvaluations);
365}
int free_zarray_2d(void **array, uint64_t n1, uint64_t n2)
Frees a 2D array and its associated memory.
Definition array.c:155

◆ rcdsMinAbort()

long rcdsMinAbort ( long abort)

Sets or queries the abort flag for the RCDS minimization.

Parameters
abortIf non-zero, sets the abort flag. If zero, queries the abort flag status.
Returns
Returns 1 if the abort flag is set, 0 otherwise.

Definition at line 28 of file rcds_powell.c.

28 {
29 if (abort) {
30 /* if zero, then operation is a query */
31 rcdsFlags |= RCDS_ABORT;
32#ifdef DEBUG
33 fprintf(stderr, "rcdsMin abort requested\n");
34#endif
35 }
36 return rcdsFlags & RCDS_ABORT ? 1 : 0;
37}

◆ scale_variables()

void scale_variables ( double * x0,
double * relative_x,
double * lowerLimit,
double * upperLimit,
long dimensions )

Definition at line 637 of file rcds_powell.c.

637 {
638 long i;
639 if (lowerLimit && upperLimit) {
640 for (i = 0; i < dimensions; i++) {
641 x0[i] = relative_x[i] * (upperLimit[i] - lowerLimit[i]) + lowerLimit[i];
642 }
643 } else {
644 memcpy(x0, relative_x, sizeof(*x0) * dimensions);
645 }
646}

◆ sort_two_arrays()

void sort_two_arrays ( double * x,
double * y,
long n )

Definition at line 868 of file rcds_powell.c.

868 {
869 double *tmpx, *tmpy;
870 long i, j;
871
872 tmpx = malloc(sizeof(*tmpx) * n);
873 memcpy(tmpx, x, sizeof(*tmpx) * n);
874 tmpy = malloc(sizeof(*tmpy) * n);
875
876 qsort(tmpx, n, sizeof(*tmpx), double_cmpasc);
877 for (i = 0; i < n; i++) {
878 for (j = 0; j < n; j++) {
879 if (tmpx[i] == x[j])
880 break;
881 }
882 tmpy[i] = y[j];
883 }
884 for (i = 0; i < n; i++) {
885 y[i] = tmpy[i];
886 x[i] = tmpx[i];
887 }
888 free(tmpx);
889 free(tmpy);
890 return;
891}