225 double **simplexVector,
227 double *coordLowerLimit,
228 double *coordUpperLimit,
231 long activeDimensions,
235 double (*function)(
double *x,
long *invalid),
238 unsigned long flags) {
239 long point, points, invalids, degenerates, isDegenerate, isInvalid;
240 long direction, bestPoint, worstPoint, nextWorstPoint;
241 double fTrial, fProblem, fWorst, fBest, merit, denominator;
242 double *simplexCenter = NULL, *tmpVector;
243 short usedLast, usedLastCount = 0, newPoint;
244 long reflectionWorked = 0, extensionWorked = 0, contractionWorked = 0, shrinkingDone = 0;
247 simplexCenter =
tmalloc(
sizeof(*simplexCenter) * (dimensions));
248 tmpVector =
tmalloc(
sizeof(*tmpVector) * (dimensions));
251 if (maxEvaluations <= 0)
252 maxEvaluations = DEFAULT_MAXEVALS;
254 computeSimplexCenter(simplexCenter, simplexVector, dimensions, activeDimensions);
256 points = activeDimensions + 1;
257 while (*evaluations < maxEvaluations && !(simplexFlags & SIMPLEX_ABORT)) {
262 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
263 fprintf(stdout,
"simplexMinimization: finding best and worst points\n");
266 simplexFindBestWorst(fValue, points, &bestPoint, &worstPoint, &nextWorstPoint);
267 fBest = fValue[bestPoint];
268 fWorst = fValue[worstPoint];
270 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
271 fprintf(stdout,
"simplexMinimization: evaluating present results\n");
275 if (tolerance_mode == 0) {
277 if ((denominator = (fabs(fWorst) + fabs(fBest)) / 2))
278 merit = fabs(fWorst - fBest) / denominator;
280 fputs(
"error: divide-by-zero in fractional tolerance evaluation (simplexMinimization)\n", stderr);
287 merit = fabs(fWorst - fBest);
288 if (merit < tolerance || fBest <= target) {
290 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
291 fprintf(stdout,
"simplexMinimization: tolerance exceed or value small enough\n");
298 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
299 fprintf(stdout,
"simplexMinimization: Reflecting simplex\n");
303 fTrial = trialSimplex(simplexVector, fValue, simplexCenter, coordLowerLimit,
304 coordUpperLimit, disable, dimensions, activeDimensions, function,
305 worstPoint, evaluations, -1.0, &usedLast, &newPoint);
306 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
307 fprintf(stdout,
"simplexMinization: reflection returns (newPoint=%d)\n", newPoint);
310 reflectionWorked += newPoint ? 1 : 0;
311 progressMade += newPoint;
316 if (usedLastCount > 2) {
317 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
318 fprintf(stdout,
"simplexMinization: simplex is looping--ending iterations\n");
324 if (fTrial < fValue[bestPoint]) {
329 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
330 fprintf(stdout,
"simplexMinization: extending simplex\n");
333 fTrial = trialSimplex(simplexVector, fValue, simplexCenter, coordLowerLimit,
334 coordUpperLimit, disable, dimensions, activeDimensions, function,
335 worstPoint, evaluations, 2.0, &usedLast, &newPoint);
336 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
337 fprintf(stdout,
"simplexMinization: extension returns (newPoint=%d)\n", newPoint);
340 extensionWorked += newPoint ? 1 : 0;
341 progressMade += newPoint;
342 }
else if (fTrial > fValue[nextWorstPoint]) {
345 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
346 fprintf(stdout,
"simplexMinization: contracting simplex\n");
350 fTrial = trialSimplex(simplexVector, fValue, simplexCenter, coordLowerLimit,
351 coordUpperLimit, disable, dimensions, activeDimensions, function,
352 worstPoint, evaluations, 0.5, &usedLast, &newPoint);
353 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
354 fprintf(stdout,
"simplexMinization: contraction returns (newPoint=%d)\n", newPoint);
357 contractionWorked += newPoint ? 1 : 0;
358 progressMade += newPoint;
359 if (fTrial > fProblem) {
365 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
366 fprintf(stdout,
"simplexMinimization: contracting on best point\n");
369 invalids = degenerates = 0;
370 for (point = 0; point < points; point++) {
371 if (point == bestPoint)
373 for (direction = 0; direction < dimensions; direction++)
374 tmpVector[direction] = 0.5 * (simplexVector[point][direction] + simplexVector[bestPoint][direction]);
375 for (direction = 0; direction < dimensions; direction++)
376 if (tmpVector[direction] != simplexVector[point][direction])
379 if (!(isDegenerate = direction != dimensions)) {
380 fTrial = (*function)(tmpVector, &isInvalid);
382 if (fTrial == fValue[point])
384 for (direction = 0; direction < dimensions; direction++)
385 simplexVector[point][direction] = tmpVector[direction];
386 fValue[point] = fTrial;
395 if (invalids + degenerates >= points - 1) {
396 SWAP_PTR(simplexVector[0], simplexVector[bestPoint]);
397 SWAP_DOUBLE(fValue[0], fValue[bestPoint]);
398 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
399 fprintf(stdout,
"simplexMinimization exiting: reflection: %ld extension: %ld contraction: %ld shrinking: %ld\n",
400 reflectionWorked, extensionWorked, contractionWorked, shrinkingDone);
407 *evaluations += points;
411 computeSimplexCenter(simplexCenter, simplexVector, dimensions, activeDimensions);
415 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
416 fprintf(stdout,
"simplexMinimization: Breaking out of loop--no progress.\n");
422 simplexFindBestWorst(fValue, points, &bestPoint, &worstPoint, &nextWorstPoint);
423 if (*evaluations >= maxEvaluations) {
424 SWAP_PTR(simplexVector[0], simplexVector[bestPoint]);
425 SWAP_DOUBLE(fValue[0], fValue[bestPoint]);
426 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
427 fprintf(stdout,
"simplexMinimization: too many iterations\n");
434 SWAP_PTR(simplexVector[0], simplexVector[bestPoint]);
435 SWAP_DOUBLE(fValue[0], fValue[bestPoint]);
436 if (flags & SIMPLEX_VERBOSE_LEVEL2) {
437 fprintf(stdout,
"simplexMinimization exit report: reflection: %ld extension: %ld contraction: %ld shrinking: %ld\n",
438 reflectionWorked, extensionWorked, contractionWorked, shrinkingDone);
482 double (*func)(
double *x,
long *invalid),
483 void (*report)(
double ymin,
double *xmin,
long pass,
long evals,
long dims),
487 double divisorFactor,
488 double passRangeFactor,
489 unsigned long flags) {
490 double **simplexVector = NULL, *y = NULL, *trialVector = NULL, *dxLocal = NULL;
491 long *dimIndex = NULL;
492 double yLast, dVector = 1, divisor, denominator, merit;
493 long direction, point, evaluations, totalEvaluations = 0, isInvalid, pass = 0, step, divisions;
494 long activeDimensions, dimension, i;
496 if (divisorFactor <= 1.0)
502 activeDimensions = 0;
503 for (direction = 0; direction < dimensions; direction++)
504 if (!disable[direction])
507 activeDimensions = dimensions;
508 if (activeDimensions <= 0)
511 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
512 fprintf(stdout,
"simplexMin: Active dimensions: %ld\n", activeDimensions);
515 simplexVector = (
double **)
zarray_2d(
sizeof(**simplexVector), activeDimensions + 1, dimensions);
516 y =
tmalloc(
sizeof(*y) * (activeDimensions + 1));
517 trialVector =
tmalloc(
sizeof(*trialVector) * activeDimensions);
518 dxLocal =
tmalloc(
sizeof(*dxLocal) * activeDimensions);
519 dimIndex =
tmalloc(
sizeof(*dimIndex) * activeDimensions);
521 for (direction = i = 0; direction < dimensions; direction++) {
522 if (!disable || !disable[direction])
523 dimIndex[i++] = direction;
525 if (i != activeDimensions) {
526 fprintf(stderr,
"Fatal error (simplexMin): active dimensions not properly counted\n");
532 for (direction = 0; direction < dimensions; direction++)
533 dxGuess[direction] = 0;
535 if (flags & SIMPLEX_RANDOM_SIGNS) {
540 for (direction = 0; direction < dimensions; direction++) {
541 if (dxGuess[direction] == 0) {
542 if (xLowerLimit && xUpperLimit)
543 dxGuess[direction] = (xUpperLimit[direction] - xLowerLimit[direction]) / 4;
544 else if ((dxGuess[direction] = xGuess[direction] / 4) == 0)
545 dxGuess[direction] = 1;
547 if (flags & SIMPLEX_RANDOM_SIGNS) {
548 if (rand() > RAND_MAX / 2.0)
549 dxGuess[direction] *= -1;
551 if (xLowerLimit && xUpperLimit) {
552 if ((dVector = fabs(xUpperLimit[direction] - xLowerLimit[direction]) / 4) < fabs(dxGuess[direction]))
553 dxGuess[direction] = dVector;
555 if (disable && disable[direction])
556 dxGuess[direction] = 0;
561 for (direction = 0; direction < dimensions; direction++)
562 if (xLowerLimit[direction] >= xGuess[direction])
563 dxGuess[direction] = fabs(dxGuess[direction]);
567 for (direction = 0; direction < dimensions; direction++)
568 if (xUpperLimit[direction] <= xGuess[direction])
569 dxGuess[direction] = -fabs(dxGuess[direction]);
571 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
572 fprintf(stdout,
"simplexMin: starting conditions:\n");
573 for (direction = 0; direction < dimensions; direction++)
574 fprintf(stdout,
"direction %ld: guess=%le delta=%le disable=%hd\n",
575 direction, xGuess[direction], dxGuess[direction],
576 disable ? disable[direction] : (
short)0);
581 maxPasses = DEFAULT_MAXPASSES;
586 for (point = 0; point < activeDimensions + 1; point++)
589 while (pass < maxPasses && !(simplexFlags & SIMPLEX_ABORT)) {
592 for (direction = 0; direction < dimensions; direction++)
593 simplexVector[0][direction] = xGuess[direction];
594 *yReturn = y[0] = (*func)(simplexVector[0], &isInvalid);
598 fprintf(stderr,
"error: initial guess is invalid in simplexMin()\n");
599 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
606 if (y[0] <= target) {
607 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
608 fprintf(stdout,
"simplexMin: target value achieved in initial simplex setup.\n");
612 (*report)(y[0], simplexVector[0], pass, totalEvaluations, dimensions);
613 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
618 return (totalEvaluations);
623 for (point = 1; !(simplexFlags & SIMPLEX_ABORT) && point < activeDimensions + 1; point++) {
624 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
625 fprintf(stdout,
"simplexMin: Setting initial simplex for direction %ld\n", point - 1);
628 dimension = dimIndex[point - 1];
629 if (!(flags & SIMPLEX_NO_1D_SCANS)) {
633 for (direction = 0; direction < dimensions; direction++)
634 simplexVector[point][direction] = simplexVector[(flags & SIMPLEX_START_FROM_VERTEX1) ? 0 : point - 1][direction];
639 yLast = y[point - 1];
640 while (divisions < maxDivisions && !(simplexFlags & SIMPLEX_ABORT)) {
641 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
642 fprintf(stdout,
"simplexMin: working on division %ld (divisor=%e) for direction %ld\n",
643 divisions, divisor, point - 1);
646 simplexVector[point][dimension] = simplexVector[point - 1][dimension] + dxGuess[dimension] / divisor;
647 if ((xLowerLimit || xUpperLimit) &&
648 !checkVariableLimits(simplexVector[point], xLowerLimit, xUpperLimit, dimensions)) {
651 fprintf(stdout,
" Point outside of bounds:\n");
653 for (idum = 0; idum < dimensions; idum++)
654 fprintf(stdout,
" %le %le, %le\n", simplexVector[point][idum],
655 xLowerLimit[idum], xUpperLimit[idum]);
661 y[point] = (*func)(simplexVector[point], &isInvalid);
665 fprintf(stdout,
" Point is invalid\n");
671 if (y[point] <= target) {
672 for (direction = 0; direction < dimensions; direction++)
673 xGuess[direction] = simplexVector[point][direction];
676 (*report)(*yReturn, xGuess, pass, totalEvaluations, dimensions);
677 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
678 fprintf(stdout,
"simplexMin: invalid function status. Returning.\n");
681 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
686 return (totalEvaluations);
689 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
690 fprintf(stdout,
"simplexMin: New value: %le Last value: %le\n", y[point], yLast);
693 if (y[point] < yLast)
702 divisor *= divisorFactor;
705 if ((flags & SIMPLEX_NO_1D_SCANS) || divisions == maxDivisions) {
706 for (direction = 0; direction < dimensions; direction++)
707 simplexVector[point][direction] = simplexVector[0][direction];
712 yLast = y[point - 1];
713 while (divisions < maxDivisions && !(simplexFlags & SIMPLEX_ABORT)) {
715 fprintf(stdout,
"Trying divisor %ld\n", divisions);
718 simplexVector[point][dimension] = simplexVector[0][dimension] +
719 dxGuess[dimension] / divisor;
720 if ((xLowerLimit || xUpperLimit) &&
721 !checkVariableLimits(simplexVector[point], xLowerLimit, xUpperLimit, dimensions)) {
724 y[point] = (*func)(simplexVector[point], &isInvalid);
728 fprintf(stdout,
" Point is invalid\n");
744 if (divisions == maxDivisions) {
745 fprintf(stderr,
"error: can't find valid initial simplex in simplexMin()\n");
746 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
755 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
756 fprintf(stdout,
"simplexMin: decrease found---trying more steps\n");
760 for (step = 0; !(simplexFlags & SIMPLEX_ABORT) && step < 3; step++) {
761 divisor /= divisorFactor;
762 simplexVector[point][dimension] += dxGuess[dimension] / divisor;
763 if ((xLowerLimit || xUpperLimit) &&
764 !checkVariableLimits(simplexVector[point], xLowerLimit, xUpperLimit, dimensions)) {
765 simplexVector[point][dimension] -= dxGuess[dimension] / divisor;
769 y[point] = (*func)(simplexVector[point], &isInvalid);
771 if (isInvalid || y[point] > yLast) {
772 simplexVector[point][dimension] -= dxGuess[dimension] / divisor;
776 if (y[point] <= target) {
777 for (direction = 0; direction < dimensions; direction++)
778 xGuess[direction] = simplexVector[point][direction];
781 (*report)(*yReturn, xGuess, pass, totalEvaluations, dimensions);
782 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
783 fprintf(stdout,
"simplexMin: value below target during 1D scan---returning\n");
786 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
791 return totalEvaluations;
797 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
798 fprintf(stdout,
"simplexMin: Starting simplex: \n");
799 for (point = 0; point < activeDimensions + 1; point++) {
800 fprintf(stdout,
"V%2ld %.5g: ", point, y[point]);
801 for (direction = 0; direction < dimensions; direction++)
802 fprintf(stdout,
"%.5g ", simplexVector[point][direction]);
803 fprintf(stdout,
"\n");
808 if (simplexFlags & SIMPLEX_ABORT) {
810 for (point = 1; point < activeDimensions + 1; point++)
811 if (y[point] < y[best])
813 for (direction = 0; direction < dimensions; direction++)
814 xGuess[direction] = simplexVector[best][direction];
815 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
816 fprintf(stdout,
"simplexMin: abort received before simplex began---returning\n");
819 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
824 return totalEvaluations;
829 dimensions, activeDimensions, target,
830 fabs(tolerance), (tolerance < 0 ? 0 : 1), func, maxEvaluations, &evaluations,
832 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
833 fprintf(stdout,
"simplexMin: returned from simplexMinimization after %ld evaluations\n",
837 totalEvaluations += evaluations;
838 for (point = 1; point < activeDimensions + 1; point++) {
839 if (y[0] > y[point]) {
840 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
845 bomb(
"problem with ordering of data from simplexMinimization", NULL);
850 for (direction = 0; direction < dimensions; direction++)
851 xGuess[direction] = simplexVector[0][direction];
854 (*report)(y[0], simplexVector[0], pass, totalEvaluations, dimensions);
856 if (y[0] <= target || (simplexFlags & SIMPLEX_ABORT)) {
858 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
859 fprintf(stdout,
"simplexMin: target value achieved---returning\n");
862 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
867 return (totalEvaluations);
870 if (tolerance <= 0) {
871 denominator = (y[0] + (*yReturn)) / 2;
873 merit = fabs(y[0] - (*yReturn)) / denominator;
875 fputs(
"error: divide-by-zero in fractional tolerance evaluation (simplexMin)\n", stderr);
876 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
884 merit = fabs(y[0] - (*yReturn));
885 if (merit <= fabs(tolerance) || y[0] <= target)
889 for (direction = 0; direction < dimensions; direction++) {
891 min = max = simplexVector[0][direction];
892 for (point = 1; point < activeDimensions + 1; point++) {
893 if (simplexVector[point][direction] > max)
894 max = simplexVector[point][direction];
895 if (simplexVector[point][direction] < min)
896 min = simplexVector[point][direction];
899 dxGuess[direction] = passRangeFactor * (max - min);
903 if (flags & SIMPLEX_VERBOSE_LEVEL1) {
904 fprintf(stdout,
"simplexMin: iterations exhausted---returning\n");
909 free_zarray_2d((
void **)simplexVector, activeDimensions + 1, dimensions);
915 if (pass > maxPasses)
917 return (totalEvaluations);