# include # include # include # include # include using namespace std; double best_nearby(double delta[], double point[], double prevbest, int nvars, double f(double x[], int nvars), int *funevals); int hooke(int nvars, double startpt[], double endpt[], double rho, double eps, int itermax, double f(double x[], int nvars)); double r8_abs(double x); void timestamp(void); int main(); double rosenbrock(double x[], int n); double best_nearby(double delta[], double point[], double prevbest, int nvars, double f ( double x[], int nvars ), int *funevals) { double ftmp; int i; double minf; double *z; z = new double[nvars]; minf = prevbest; for (i = 0; i < nvars; i++) { z[i] = point[i]; } for (i = 0; i < nvars; i++) { z[i] = point[i] + delta[i]; ftmp = f ( z, nvars ); *funevals = *funevals + 1; if (ftmp < minf) { minf = ftmp; } else { delta[i] = - delta[i]; z[i] = point[i] + delta[i]; ftmp = f ( z, nvars ); *funevals = *funevals + 1; if (ftmp < minf) { minf = ftmp; } else { z[i] = point[i]; } } } for (i = 0; i < nvars; i++) { point[i] = z[i]; } delete [] z; return minf; } int hooke(int nvars, double startpt[], double endpt[], double rho, double eps, int itermax, double f(double x[], int nvars)) { double *delta; double fbefore; int funevals; int i; int iters; int keep; double newf; double *newx; double steplength; double tmp; bool verbose = true; double *xbefore; delta = new double[nvars]; newx = new double[nvars]; xbefore = new double[nvars]; for (i = 0; i < nvars; i++) { newx[i] = startpt[i]; } for (i = 0; i < nvars; i++) { xbefore[i] = startpt[i]; } for (i = 0; i < nvars; i++) { if (startpt[i] == 0.0) { delta[i] = rho; } else { delta[i] = rho * r8_abs (startpt[i]); } } funevals = 0; steplength = rho; iters = 0; fbefore = f ( newx, nvars ); funevals = funevals + 1; newf = fbefore; while (iters < itermax && eps < steplength) { iters = iters + 1; if (verbose) { cout << "\n"; cout << " FUNEVALS, = " << funevals << " F(X) = " << fbefore << "\n"; for ( i = 0; i < nvars; i++ ) { cout << " " << i + 1 << " " << xbefore[i] << "\n"; } } // // Find best new point, one coordinate at a time. // for (i = 0; i < nvars; i++) { newx[i] = xbefore[i]; } newf = best_nearby ( delta, newx, fbefore, nvars, f, &funevals ); // // If we made some improvements, pursue that direction. // keep = 1; while (newf < fbefore && keep == 1) { for (i = 0; i < nvars; i++) { // // Arrange the sign of DELTA. // if (newx[i] <= xbefore[i]) { delta[i] = - r8_abs (delta[i]); } else { delta[i] = r8_abs (delta[i]); } // // Now, move further in this direction. // tmp = xbefore[i]; xbefore[i] = newx[i]; newx[i] = newx[i] + newx[i] - tmp; } fbefore = newf; newf = best_nearby (delta, newx, fbefore, nvars, f, &funevals); // // If the further (optimistic) move was bad... // if (fbefore <= newf) { break; } // // Make sure that the differences between the new and the old points // are due to actual displacements; beware of roundoff errors that // might cause NEWF < FBEFORE. // keep = 0; for (i = 0; i < nvars; i++) { if (0.5 * r8_abs(delta[i]) < r8_abs(newx[i] - xbefore[i])) { keep = 1; break; } } } if (eps <= steplength && fbefore <= newf) { steplength = steplength * rho; for (i = 0; i < nvars; i++) { delta[i] = delta[i] * rho; } } } for (i = 0; i < nvars; i++) { endpt[i] = xbefore[i]; } delete [] delta; delete [] newx; delete [] xbefore; return iters; } double r8_abs(double x) { double value; if (0.0 <= x) { value = x; } else { value = -x; } return value; } void timestamp(void) { # define TIME_SIZE 40 static char time_buffer[TIME_SIZE]; const struct tm *tm; size_t len; time_t now; now = time(NULL); tm = localtime(&now); len = strftime(time_buffer, TIME_SIZE, "%d %B %Y %I:%M:%S %p", tm); cout << time_buffer << "\n"; return; # undef TIME_SIZE } int main() { timestamp(); double *endpt; double eps; int i; int it; int itermax; int nvars = 2; double rho; double *startpt; double value; endpt = new double[nvars]; startpt = new double[nvars]; cout << "\n"; cout << " HOOKE seeks a minimizer of F(X).\n"; cout << " Here we use the Rosenbrock function.\n"; // // Starting guess for Rosenbrock. // startpt[0] = 0.0; startpt[1] = 0.0; cout << "\n"; cout << " Initial estimate X =\n"; cout << "\n"; for (i = 0; i < nvars; i++) { cout << " " << setw(8) << i + 1 << " " << setw(14) << startpt[i] << "\n"; } value = rosenbrock(startpt, nvars); cout << "\n"; cout << " F(X) = " << value << "\n"; // // Call HOOKE. // itermax = 5000; rho = 0.5; eps = 1.0E-06; it = hooke(nvars, startpt, endpt, rho, eps, itermax, &rosenbrock); // // Results. // cout << "\n"; cout << " Number of iterations taken = " << it << "\n"; cout << "\n"; cout << " X* = \n"; cout << "\n"; for (i = 0; i < nvars; i++) { cout << " " << setw(8) << i + 1 << " " << setw(14) << endpt[i] << "\n"; } value = rosenbrock(endpt, nvars); cout << "\n"; cout << " F(X*) = " << value << "\n"; delete [] endpt; delete [] startpt; cout << " Normal end of execution.\n"; cout << "\n"; timestamp(); return 0; } double rosenbrock(double x[], int n) { return x[0]*x[0] - 2*sin(x[1]) + 1.85*x[1]*x[1]; }