SDDSlib
Loading...
Searching...
No Matches
rcds_powell.c File Reference

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

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

Go to the source code of this file.

Macros

#define DEFAULT_MAXEVALS   100
 
#define DEFAULT_MAXPASSES   5
 
#define DEBUG   0
 
#define RCDS_ABORT   0x0001UL
 

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.
 

Variables

static unsigned long rcdsFlags = 0
 
static long DIMENSIONS
 

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.

Macro Definition Documentation

◆ DEBUG

#define DEBUG   0

Definition at line 17 of file rcds_powell.c.

◆ DEFAULT_MAXEVALS

#define DEFAULT_MAXEVALS   100

Definition at line 14 of file rcds_powell.c.

◆ DEFAULT_MAXPASSES

#define DEFAULT_MAXPASSES   5

Definition at line 15 of file rcds_powell.c.

◆ RCDS_ABORT

#define RCDS_ABORT   0x0001UL

Definition at line 19 of file rcds_powell.c.

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

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

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

◆ outlier_1d()

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

Definition at line 908 of file rcds_powell.c.

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

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

◆ sort_two_arrays()

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

Definition at line 867 of file rcds_powell.c.

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

Variable Documentation

◆ DIMENSIONS

long DIMENSIONS
static

Definition at line 80 of file rcds_powell.c.

◆ rcdsFlags

unsigned long rcdsFlags = 0
static

Definition at line 20 of file rcds_powell.c.