255 double **simplexVector,
257 double *coordLowerLimit,
258 double *coordUpperLimit,
261 long activeDimensions,
265 double (*function)(
double *x,
long *invalid),
268 unsigned long flags) {
269 long point, points, invalids, degenerates, isDegenerate, isInvalid;
270 long direction, bestPoint, worstPoint, nextWorstPoint;
271 double fTrial, fProblem, fWorst, fBest, merit, denominator;
272 double *simplexCenter = NULL, *tmpVector;
273 short usedLast, usedLastCount = 0, newPoint;
274 long reflectionWorked = 0, extensionWorked = 0, contractionWorked = 0, shrinkingDone = 0;
277 simplexCenter =
tmalloc(
sizeof(*simplexCenter) * (dimensions));
278 tmpVector =
tmalloc(
sizeof(*tmpVector) * (dimensions));
281 if (maxEvaluations <= 0)
282 maxEvaluations = DEFAULT_MAXEVALS;
284 computeSimplexCenter(simplexCenter, simplexVector, dimensions, activeDimensions);
286 points = activeDimensions + 1;
287 while (*evaluations < maxEvaluations && !simplexAbortRequested()) {
292 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
293 fprintf(stdout,
"simplexMinimization: finding best and worst points\n");
296 simplexFindBestWorst(fValue, points, &bestPoint, &worstPoint, &nextWorstPoint);
297 fBest = fValue[bestPoint];
298 fWorst = fValue[worstPoint];
300 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
301 fprintf(stdout,
"simplexMinimization: evaluating present results\n");
305 if (tolerance_mode == 0) {
307 if ((denominator = (fabs(fWorst) + fabs(fBest)) / 2))
308 merit = fabs(fWorst - fBest) / denominator;
310 fputs(
"error: divide-by-zero in fractional tolerance evaluation (simplexMinimization)\n", stderr);
317 merit = fabs(fWorst - fBest);
318 if (merit < tolerance || fBest <= target) {
320 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
321 fprintf(stdout,
"simplexMinimization: tolerance exceed or value small enough\n");
328 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
329 fprintf(stdout,
"simplexMinimization: Reflecting simplex\n");
333 fTrial = trialSimplex(simplexVector, fValue, simplexCenter, coordLowerLimit,
334 coordUpperLimit, disable, dimensions, activeDimensions, function,
335 worstPoint, evaluations, -1.0, &usedLast, &newPoint);
336 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
337 fprintf(stdout,
"simplexMinization: reflection returns (newPoint=%d)\n", newPoint);
340 reflectionWorked += newPoint ? 1 : 0;
341 progressMade += newPoint;
346 if (usedLastCount > 2) {
347 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
348 fprintf(stdout,
"simplexMinization: simplex is looping--ending iterations\n");
354 if (fTrial < fValue[bestPoint]) {
359 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
360 fprintf(stdout,
"simplexMinization: extending simplex\n");
363 fTrial = trialSimplex(simplexVector, fValue, simplexCenter, coordLowerLimit,
364 coordUpperLimit, disable, dimensions, activeDimensions, function,
365 worstPoint, evaluations, 2.0, &usedLast, &newPoint);
366 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
367 fprintf(stdout,
"simplexMinization: extension returns (newPoint=%d)\n", newPoint);
370 extensionWorked += newPoint ? 1 : 0;
371 progressMade += newPoint;
372 }
else if (fTrial > fValue[nextWorstPoint]) {
375 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
376 fprintf(stdout,
"simplexMinization: contracting simplex\n");
380 fTrial = trialSimplex(simplexVector, fValue, simplexCenter, coordLowerLimit,
381 coordUpperLimit, disable, dimensions, activeDimensions, function,
382 worstPoint, evaluations, 0.5, &usedLast, &newPoint);
383 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
384 fprintf(stdout,
"simplexMinization: contraction returns (newPoint=%d)\n", newPoint);
387 contractionWorked += newPoint ? 1 : 0;
388 progressMade += newPoint;
389 if (fTrial > fProblem) {
395 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
396 fprintf(stdout,
"simplexMinimization: contracting on best point\n");
399 invalids = degenerates = 0;
400 for (point = 0; point < points; point++) {
401 if (point == bestPoint)
403 for (direction = 0; direction < dimensions; direction++)
404 tmpVector[direction] = 0.5 * (simplexVector[point][direction] + simplexVector[bestPoint][direction]);
405 for (direction = 0; direction < dimensions; direction++)
406 if (tmpVector[direction] != simplexVector[point][direction])
409 if (!(isDegenerate = direction != dimensions)) {
410 fTrial = (*function)(tmpVector, &isInvalid);
412 if (fTrial == fValue[point])
414 for (direction = 0; direction < dimensions; direction++)
415 simplexVector[point][direction] = tmpVector[direction];
416 fValue[point] = fTrial;
425 if (invalids + degenerates >= points - 1) {
426 SWAP_PTR(simplexVector[0], simplexVector[bestPoint]);
427 SWAP_DOUBLE(fValue[0], fValue[bestPoint]);
428 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
429 fprintf(stdout,
"simplexMinimization exiting: reflection: %ld extension: %ld contraction: %ld shrinking: %ld\n",
430 reflectionWorked, extensionWorked, contractionWorked, shrinkingDone);
437 *evaluations += points;
441 computeSimplexCenter(simplexCenter, simplexVector, dimensions, activeDimensions);
445 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
446 fprintf(stdout,
"simplexMinimization: Breaking out of loop--no progress.\n");
452 simplexFindBestWorst(fValue, points, &bestPoint, &worstPoint, &nextWorstPoint);
453 if (*evaluations >= maxEvaluations) {
454 SWAP_PTR(simplexVector[0], simplexVector[bestPoint]);
455 SWAP_DOUBLE(fValue[0], fValue[bestPoint]);
456 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
457 fprintf(stdout,
"simplexMinimization: too many iterations\n");
464 SWAP_PTR(simplexVector[0], simplexVector[bestPoint]);
465 SWAP_DOUBLE(fValue[0], fValue[bestPoint]);
466 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
467 fprintf(stdout,
"simplexMinimization exit report: reflection: %ld extension: %ld contraction: %ld shrinking: %ld\n",
468 reflectionWorked, extensionWorked, contractionWorked, shrinkingDone);
512 double (*func)(
double *x,
long *invalid),
513 void (*report)(
double ymin,
double *xmin,
long pass,
long evals,
long dims),
517 double divisorFactor,
518 double passRangeFactor,
519 unsigned long flags) {
520 double **simplexVector = NULL, *y = NULL, *trialVector = NULL, *dxLocal = NULL;
521 long *dimIndex = NULL;
522 double yLast, dVector = 1, divisor, denominator, merit;
523 long direction, point, evaluations, totalEvaluations = 0, isInvalid, pass = 0, step, divisions;
524 long activeDimensions, dimension, i;
527 if (divisorFactor <= 1.0)
533 activeDimensions = 0;
534 for (direction = 0; direction < dimensions; direction++)
535 if (!disable[direction])
538 activeDimensions = dimensions;
539 if (activeDimensions <= 0)
542 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
543 fprintf(stdout,
"simplexMin: Active dimensions: %ld\n", activeDimensions);
546 simplexVector = (
double **)
zarray_2d(
sizeof(**simplexVector), activeDimensions + 1, dimensions);
547 y =
tmalloc(
sizeof(*y) * (activeDimensions + 1));
548 trialVector =
tmalloc(
sizeof(*trialVector) * activeDimensions);
549 dxLocal =
tmalloc(
sizeof(*dxLocal) * activeDimensions);
550 dimIndex =
tmalloc(
sizeof(*dimIndex) * activeDimensions);
552 for (direction = i = 0; direction < dimensions; direction++) {
553 if (!disable || !disable[direction])
554 dimIndex[i++] = direction;
556 if (i != activeDimensions) {
557 fprintf(stderr,
"Fatal error (simplexMin): active dimensions not properly counted\n");
563 for (direction = 0; direction < dimensions; direction++)
564 dxGuess[direction] = 0;
566 randomSigns = flags & SIMPLEX_RANDOM_SIGNS;
571 mdbmth_srand_unlocked((
unsigned int)intTime);
573 for (direction = 0; direction < dimensions; direction++) {
574 if (dxGuess[direction] == 0) {
575 if (xLowerLimit && xUpperLimit)
576 dxGuess[direction] = (xUpperLimit[direction] - xLowerLimit[direction]) / 4;
577 else if ((dxGuess[direction] = xGuess[direction] / 4) == 0)
578 dxGuess[direction] = 1;
581 if (mdbmth_rand_unlocked() > RAND_MAX / 2.0)
582 dxGuess[direction] *= -1;
584 if (xLowerLimit && xUpperLimit) {
585 if ((dVector = fabs(xUpperLimit[direction] - xLowerLimit[direction]) / 4) < fabs(dxGuess[direction]))
586 dxGuess[direction] = dVector;
588 if (disable && disable[direction])
589 dxGuess[direction] = 0;
592 mdbmth_unlock_rand();
596 for (direction = 0; direction < dimensions; direction++)
597 if (xLowerLimit[direction] >= xGuess[direction])
598 dxGuess[direction] = fabs(dxGuess[direction]);
602 for (direction = 0; direction < dimensions; direction++)
603 if (xUpperLimit[direction] <= xGuess[direction])
604 dxGuess[direction] = -fabs(dxGuess[direction]);
606 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
607 fprintf(stdout,
"simplexMin: starting conditions:\n");
608 for (direction = 0; direction < dimensions; direction++)
609 fprintf(stdout,
"direction %ld: guess=%le delta=%le disable=%hd, min=%le, max=%le\n",
610 direction, xGuess[direction], dxGuess[direction],
611 disable ? disable[direction] : (
short)0,
612 xLowerLimit ? xLowerLimit[direction] : -DBL_MAX,
613 xUpperLimit ? xUpperLimit[direction] : DBL_MAX);
618 maxPasses = DEFAULT_MAXPASSES;
623 for (point = 0; point < activeDimensions + 1; point++)
626 while (pass < maxPasses && !simplexAbortRequested()) {
629 for (direction = 0; direction < dimensions; direction++)
630 simplexVector[0][direction] = xGuess[direction];
631 *yReturn = y[0] = (*func)(simplexVector[0], &isInvalid);
635 fprintf(stderr,
"error: initial guess is invalid in simplexMin()\n");
636 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
643 if (y[0] <= target) {
644 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
645 fprintf(stdout,
"simplexMin: target value achieved in initial simplex setup.\n");
649 (*report)(y[0], simplexVector[0], pass, totalEvaluations, dimensions);
650 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
655 return (totalEvaluations);
660 for (point = 1; !simplexAbortRequested() && point < activeDimensions + 1; point++) {
661 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
662 fprintf(stdout,
"simplexMin: Setting initial simplex for direction %ld\n", point - 1);
665 dimension = dimIndex[point - 1];
666 if (!(flags & SIMPLEX_NO_1D_SCANS)) {
670 for (direction = 0; direction < dimensions; direction++)
671 simplexVector[point][direction] = simplexVector[(flags & SIMPLEX_START_FROM_VERTEX1) ? 0 : point - 1][direction];
676 yLast = y[point - 1];
677 while (divisions < maxDivisions && !simplexAbortRequested()) {
678 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
679 fprintf(stdout,
"simplexMin: working on division %ld (divisor=%e) for direction %ld\n",
680 divisions, divisor, point - 1);
683 simplexVector[point][dimension] = simplexVector[point - 1][dimension] + dxGuess[dimension] / divisor;
684 if ((xLowerLimit || xUpperLimit) &&
685 !checkVariableLimits(simplexVector[point], xLowerLimit, xUpperLimit, disable, dimensions)) {
688 fprintf(stdout,
" Point outside of bounds:\n");
690 for (idum = 0; idum < dimensions; idum++)
691 fprintf(stdout,
" %le %le, %le\n", simplexVector[point][idum],
692 xLowerLimit[idum], xUpperLimit[idum]);
699 fprintf(stdout,
" Evaluating point\n");
702 y[point] = (*func)(simplexVector[point], &isInvalid);
706 fprintf(stdout,
" Point is invalid\n");
712 if (y[point] <= target) {
713 for (direction = 0; direction < dimensions; direction++)
714 xGuess[direction] = simplexVector[point][direction];
717 (*report)(*yReturn, xGuess, pass, totalEvaluations, dimensions);
718 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
719 fprintf(stdout,
"simplexMin: invalid function status. Returning.\n");
722 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
727 return (totalEvaluations);
730 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
731 fprintf(stdout,
"simplexMin: New value: %le Last value: %le\n", y[point], yLast);
734 if (y[point] < yLast)
743 divisor *= divisorFactor;
746 if ((flags & SIMPLEX_NO_1D_SCANS) || divisions == maxDivisions) {
747 for (direction = 0; direction < dimensions; direction++)
748 simplexVector[point][direction] = simplexVector[0][direction];
753 yLast = y[point - 1];
754 while (divisions < maxDivisions && !simplexAbortRequested()) {
756 fprintf(stdout,
"Trying divisor %ld\n", divisions);
759 simplexVector[point][dimension] = simplexVector[0][dimension] +
760 dxGuess[dimension] / divisor;
761 if ((xLowerLimit || xUpperLimit) &&
762 !checkVariableLimits(simplexVector[point], xLowerLimit, xUpperLimit, disable, dimensions)) {
765 y[point] = (*func)(simplexVector[point], &isInvalid);
769 fprintf(stdout,
" Point is invalid\n");
785 if (divisions == maxDivisions) {
786 fprintf(stderr,
"error: can't find valid initial simplex in simplexMin()\n");
787 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
796 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
797 fprintf(stdout,
"simplexMin: decrease found---trying more steps\n");
801 for (step = 0; !simplexAbortRequested() && step < 3; step++) {
802 divisor /= divisorFactor;
803 simplexVector[point][dimension] += dxGuess[dimension] / divisor;
804 if ((xLowerLimit || xUpperLimit) &&
805 !checkVariableLimits(simplexVector[point], xLowerLimit, xUpperLimit, disable, dimensions)) {
806 simplexVector[point][dimension] -= dxGuess[dimension] / divisor;
810 y[point] = (*func)(simplexVector[point], &isInvalid);
812 if (isInvalid || y[point] > yLast) {
813 simplexVector[point][dimension] -= dxGuess[dimension] / divisor;
817 if (y[point] <= target) {
818 for (direction = 0; direction < dimensions; direction++)
819 xGuess[direction] = simplexVector[point][direction];
822 (*report)(*yReturn, xGuess, pass, totalEvaluations, dimensions);
823 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
824 fprintf(stdout,
"simplexMin: value below target during 1D scan---returning\n");
827 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
832 return totalEvaluations;
838 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
839 fprintf(stdout,
"simplexMin: Starting simplex: \n");
840 for (point = 0; point < activeDimensions + 1; point++) {
841 fprintf(stdout,
"V%2ld %.5g: ", point, y[point]);
842 for (direction = 0; direction < dimensions; direction++)
843 fprintf(stdout,
"%.5g ", simplexVector[point][direction]);
844 fprintf(stdout,
"\n");
849 if (simplexAbortRequested()) {
851 for (point = 1; point < activeDimensions + 1; point++)
852 if (y[point] < y[best])
854 for (direction = 0; direction < dimensions; direction++)
855 xGuess[direction] = simplexVector[best][direction];
856 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
857 fprintf(stdout,
"simplexMin: abort received before simplex began---returning\n");
860 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
865 return totalEvaluations;
870 dimensions, activeDimensions, target,
871 fabs(tolerance), (tolerance < 0 ? 0 : 1), func, maxEvaluations, &evaluations,
873 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
874 fprintf(stdout,
"simplexMin: returned from simplexMinimization after %ld evaluations\n",
878 totalEvaluations += evaluations;
879 for (point = 1; point < activeDimensions + 1; point++) {
880 if (y[0] > y[point]) {
881 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
886 bomb(
"problem with ordering of data from simplexMinimization", NULL);
891 for (direction = 0; direction < dimensions; direction++)
892 xGuess[direction] = simplexVector[0][direction];
895 (*report)(y[0], simplexVector[0], pass, totalEvaluations, dimensions);
897 if (y[0] <= target || simplexAbortRequested()) {
899 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
900 fprintf(stdout,
"simplexMin: target value achieved---returning\n");
903 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
908 return (totalEvaluations);
911 if (tolerance <= 0) {
912 denominator = (y[0] + (*yReturn)) / 2;
914 merit = fabs(y[0] - (*yReturn)) / denominator;
916 fputs(
"error: divide-by-zero in fractional tolerance evaluation (simplexMin)\n", stderr);
917 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
925 merit = fabs(y[0] - (*yReturn));
926 if (merit <= fabs(tolerance) || y[0] <= target)
930 for (direction = 0; direction < dimensions; direction++) {
932 min = max = simplexVector[0][direction];
933 for (point = 1; point < activeDimensions + 1; point++) {
934 if (simplexVector[point][direction] > max)
935 max = simplexVector[point][direction];
936 if (simplexVector[point][direction] < min)
937 min = simplexVector[point][direction];
940 dxGuess[direction] = passRangeFactor * (max - min);
944 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
945 fprintf(stdout,
"simplexMin: iterations exhausted---returning\n");
950 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
956 if (pass > maxPasses)
958 return (totalEvaluations);