58 double (*func)(
double *x,
long *invalid),
59 void (*report)(
double ymin,
double *xmin,
long pass,
long evals,
long dims),
63 unsigned long flags) {
64 static double *dxLocal = NULL;
65 static long lastDimensions = 0;
66 double yLast, dVector = 1, yNew, xLocal;
67 long point, totalEvaluations = 0, isInvalid, repeats = 0, divisions;
68 long activeDimensions, direction, found = 0, stepsTaken, decreaseSeen;
69 double *divisor, *minimum, min;
76 for (direction = 0; direction < dimensions; direction++)
77 if (!disable[direction])
80 activeDimensions = dimensions;
81 if (activeDimensions <= 0)
84 if (activeDimensions > lastDimensions) {
87 dxLocal =
tmalloc(
sizeof(*dxLocal) * activeDimensions);
88 lastDimensions = activeDimensions;
90 divisor = (
double *)malloc(
sizeof(*divisor) * activeDimensions);
91 minimum = (
double *)malloc(
sizeof(*minimum) * activeDimensions);
92 for (point = 0; point < activeDimensions; point++)
93 minimum[point] = target;
96 for (direction = 0; direction < dimensions; direction++)
97 dxGuess[direction] = 0;
99 for (direction = 0; direction < dimensions; direction++)
100 dxLocal[direction] = dxGuess[direction];
103 for (direction = 0; direction < dimensions; direction++) {
104 if (dxGuess[direction] == 0) {
105 if (xLowerLimit && xUpperLimit)
106 dxGuess[direction] = (xUpperLimit[direction] - xLowerLimit[direction]) / 4;
107 else if ((dxGuess[direction] = xGuess[direction] / 4) == 0)
108 dxGuess[direction] = 1;
110 if (xLowerLimit && xUpperLimit) {
111 if ((dVector = fabs(xUpperLimit[direction] - xLowerLimit[direction]) / 4) < fabs(dxGuess[direction]))
112 dxGuess[direction] = dVector;
114 if (disable && disable[direction])
115 dxGuess[direction] = 0;
120 for (direction = 0; direction < dimensions; direction++)
121 if (xLowerLimit[direction] >= xGuess[direction])
122 dxGuess[direction] = fabs(dxGuess[direction]);
126 for (direction = 0; direction < dimensions; direction++)
127 if (xUpperLimit[direction] <= xGuess[direction])
128 dxGuess[direction] = -fabs(dxGuess[direction]);
131 for (direction = 0; direction < dimensions; direction++)
132 fprintf(stderr,
"direction %ld: guess=%le delta=%le disable=%hd\n",
133 direction, xGuess[direction], dxGuess[direction],
134 disable ? disable[direction] : (
short)0);
138 maxRepeats = DEFAULT_MAXPASSES;
139 yLast = (*func)(xGuess, &isInvalid);
142 fprintf(stderr,
"error: initial guess is invalid in simplexMin()\n");
145 if (yLast <= target) {
148 (*report)(*yReturn, xGuess, repeats, totalEvaluations, dimensions);
149 return (totalEvaluations);
151 for (point = 0; point < activeDimensions; point++)
153 while (repeats < maxRepeats) {
155 for (point = 0; point < activeDimensions; point++) {
159 xLocal = xGuess[point];
160 while (divisions < maxDivisions) {
163 while (stepsTaken < maxSteps) {
164 xGuess[point] = xGuess[point] + dxGuess[point] / divisor[point];
165 if ((xLowerLimit || xUpperLimit) &&
166 !checkVariableLimits(xGuess, xLowerLimit, xUpperLimit, dimensions)) {
169 fprintf(stderr,
" Point outside of bounds:\n");
170 for (idum = 0; idum < dimensions; idum++)
171 fprintf(stderr,
" %le %le, %le\n", xGuess[idum],
172 xLowerLimit[idum], xUpperLimit[idum]);
176 stepsTaken = maxSteps;
179 yNew = (*func)(xGuess, &isInvalid);
183 fprintf(stderr,
" Point is invalid\n");
187 if (yNew <= target) {
193 xGuess[point] = xLocal;
196 (*report)(*yReturn, xGuess, repeats, totalEvaluations, dimensions);
197 return (totalEvaluations);
199 if (fabs(yNew - yLast) <= tolerance) {
202 minimum[point] = yNew;
204 minimum[point] = yLast;
205 xGuess[point] = xLocal;
209 if (fabs(minimum[point] - min) <= tolerance) {
211 *yReturn = minimum[point];
213 (*report)(*yReturn, xGuess, repeats, totalEvaluations, dimensions);
214 return (totalEvaluations);
221 fprintf(stderr,
"decrease found, yNew=%le \n", yNew);
224 xLocal = xGuess[point];
231 xGuess[point] = xLocal;
232 stepsTaken = maxSteps;
234 fprintf(stderr,
"Increase seen: setting back to %e\n", xLocal);
236 if (flags & ONEDSCANOPTIMIZE_REFRESH) {
237 yLast = (*func)(xGuess, &isInvalid);
241 fprintf(stderr,
"error: initial guess is invalid in OneDScanOptimize()\n");
251 divisor[point] *= decreaseSeen ? -2 : -1;
259 if (minimum[activeDimensions - 1] < min)
260 min = minimum[activeDimensions - 1];
265 if (*yReturn <= target) {
267 (*report)(*yReturn, xGuess, repeats, totalEvaluations, dimensions);
268 return (totalEvaluations);
271 (*report)(*yReturn, xGuess, repeats, totalEvaluations, dimensions);
300 double xLower,
double xUpper,
301 double (*func)(
double x,
long *invalid),
302 long maxCycles,
double dxLimit,
303 double tolerance,
long maximize) {
304 double maxFactor, fBest, xBest;
306 double x0, x1 = 0, x2, f0, f1 = 0, f2;
308 maxFactor = maximize ? -1 : 1;
312 f0 = maxFactor * (*func)(x0, &invalid);
316 *yReturn = maxFactor * f0;
321 for (cycle = 0; cycle < 2 * maxCycles; cycle++) {
325 if (x1 > xUpper || x1 < xLower)
327 f1 = maxFactor * (*func)(x1, &invalid);
331 fprintf(stderr,
"cycle = %ld, maxCycles=%ld, f1 = %21.15e, fBest = %21.15e\n",
332 cycle, 2 * maxCycles, f1, fBest);
336 fprintf(stderr,
"f1<fBest\n");
343 fprintf(stderr,
"f1<f0, breaking\n");
347 dx = dx * (cycle % 2 == 0 ? -1 : -0.5);
351 if (cycle == 2 * maxCycles) {
352 if (fabs(dx) < dxLimit)
357 fprintf(stderr,
"Function decreases with dx=%e, f0=%21.15e, f1=%21.15e, cycle=%ld\n", dx, f0, f1, cycle);
363 if (x2 > xUpper || x2 < xLower)
365 f2 = maxFactor * (*func)(x2, &invalid);
373 fprintf(stderr,
"fBest = %21.15e, f1 = %21.15e, f2 = %21.15e\n",
392 for (cycle = 0; cycle < maxCycles; cycle++) {
393 double numer, denom, x3, f3, scale;
396 fprintf(stderr,
"Cycle %ld: f(%e)=%e, f(%e)=%e, f(%e)=%e\n",
397 cycle, x0, f0, x1, f1, x2, f2);
400 if (x2 == x0 || (x2 - x0) < dxLimit || (MAX(f2, f0) - f1) < tolerance)
403 numer = sqr(x1 - x0) * (f1 - f2) - sqr(x1 - x2) * (f1 - f0);
404 denom = (x1 - x0) * (f1 - f2) - (x1 - x2) * (f1 - f0);
405 x3 = x1 - numer / denom / 2.0;
409 fprintf(stderr,
"parabolic parameters: x3 = %e, f3 = %e, scale=%e, x0=%e, x2=%e\n",
411 isinf(x3) ? DBL_MAX : maxFactor * (*func)(x3, &invalid), scale, x0, x2);
413 if (!isinf(x3) && x0 < x3 && x3 < x2 &&
414 fabs(x3 - x0) > 1e-6 * scale && fabs(x3 - x1) > 1e-6 * scale &&
415 fabs(x3 - x2) > 1e-6 * scale) {
418 f3 = maxFactor * (*func)(x3, &invalid);
430 }
else if (f2 > f0 && f3 < f2) {
438 }
else if (f2 < f0 && f3 < f0) {
452 fprintf(stderr,
"Parabolic interpolation succeeded\n");
456 for (other = 0; other < 2; other++) {
458 if (fabs(x0 - x1) < fabs(x1 - x2)) {
475 f3 = maxFactor * (*func)(x3, &invalid);
483 fprintf(stderr,
"f3 = %e at x3=%e\n", f3, x3);
487 fprintf(stderr,
"Replacing point 1\n");
493 if (right && f3 < f2) {
496 fprintf(stderr,
"Replacing point 2\n");
505 }
else if (!right && f3 < f0) {
508 fprintf(stderr,
"Replacing point 0\n");
520 fprintf(stderr,
"Sectioning succeeded\n");
525 fprintf(stderr,
"Returning: x=%21.15e, y=%21.15e\n",
526 xBest, maxFactor * fBest);
528 *yReturn = maxFactor * fBest;
long OneDScanOptimize(double *yReturn, double *xGuess, double *dxGuess, double *xLowerLimit, double *xUpperLimit, short *disable, 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 maxSteps, long maxDivisions, long maxRepeats, unsigned long flags)
Performs one-dimensional scan optimization on a multi-dimensional function.