/// <summary> /// Minimizes a function on a multi-dimensional space in the vicinity of a given point, subject to the given settings. /// </summary> /// <param name="f">The function.</param> /// <param name="x">The starting point for the search.</param> /// <param name="settings">The evaluation settings.</param> /// <returns>The minimum.</returns> /// <exception cref="ArgumentNullException"><paramref name="f"/>, <paramref name="x"/>, or <paramref name="settings"/> is null.</exception> /// <exception cref="NonconvergenceException">The minimum was not found to the required precision within the budgeted number of function evaluations.</exception> internal static SpaceExtremum FindMinimum(Func <double[], double> f, double[] x, EvaluationSettings settings) { if (f == null) { throw new ArgumentNullException("f"); } if (x == null) { throw new ArgumentNullException("x"); } if (settings == null) { throw new ArgumentNullException("settings"); } int d = x.Length; // put the function into a Functor we will use for line searches LineSearchFunctor fo = new LineSearchFunctor(f); // keep track of the (conjugate) minimization directions double[][] Q = new double[d][]; for (int i = 0; i < d; i++) { Q[i] = new double[d]; for (int j = 0; j < d; j++) { Q[i][j] = 0.0; } // pick a step size in each direction that represents a fraction of the input value Q[i][i] = (1.0 / 16.0) * (Math.Abs(x[i]) + (1.0 / 16.0)); } // keep track of the curvature in these directions double[] r = new double[d]; // keep track of the function value double y = f(x); // keep track of the total number of evaluations //int count = 0; bool skip = false; // interate until convergence while (fo.EvaluationCount < settings.EvaluationBudget) { // remember our starting position double[] x0 = new double[d]; Array.Copy(x, x0, d); double y0 = y; // keep track of direction of largest decrease double max_dy = 0.0; int max_i = 0; // now minimize in each direction for (int i = 0; i < d; i++) { // if we placed the net direction in the first slot last time, // we are already at the minimum along that direction, so don't // minimize along it if (skip) { skip = false; continue; } //if ((n > 0) && (i == 0) && (max_i == 0)) continue; //Console.WriteLine("i = {0}", i); //WriteVector(Q[i]); // form a line function //LineFunction f1 = new LineFunction(f, x, Q[i]); fo.Origin = x; fo.Direction = Q[i]; // minimize it Extremum m = FindMinimum(fo, 0.0, y, 1.0, new ExtremumSettings() { EvaluationBudget = settings.EvaluationBudget, AbsolutePrecision = 0.0, RelativePrecision = 0.0 }); //LineExtremum m = FindMinimum(new Func<double,double>(f1.Evaluate), 0.0, y, 1.0); // add to the evaluation count //count += f1.Count; // update the current position x = fo.ComputeLocation(m.Location); //x = f1.Position(m.Location); //WriteVector(x); r[i] = m.Curvature; // keep track of how much the function dropped, and // if this is the direction of largest decrease double dy = y - m.Value; //Console.WriteLine("dy = {0}", dy); if (dy > max_dy) { max_dy = dy; max_i = i; } y = m.Value; } //Console.WriteLine("max_i = {0}, max_dy = {1}", max_i, max_dy); //Console.WriteLine("y0 = {0}, y = {1}", y0, y); // figure out the net direction we have moved double[] dx = new double[d]; for (int i = 0; i < d; i++) { dx[i] = x[i] - x0[i]; } //Console.WriteLine("Finish:"); //WriteVector(x); //Console.WriteLine("Net direction:"); //WriteVector(dx); // check termination criteria // we do this before minimizing in the net direction because if dx=0 it loops forever double Dy = Math.Abs(y0 - y); if ((Dy < settings.AbsolutePrecision) || (2.0 * Dy < (Math.Abs(y) + Math.Abs(y0)) * settings.RelativePrecision)) { SymmetricMatrix A = ComputeCurvature(f, x); return(new SpaceExtremum(x, y, A)); } // attempt a minimization in the net direction fo.Origin = x; fo.Direction = dx; //LineFunction f2 = new LineFunction(f, x, dx); //LineExtremum mm = FindMinimum(new Func<double,double>(f2.Evaluate), 0.0, y, 1.0); Extremum mm = FindMinimum(fo, 0.0, y, 1.0, new ExtremumSettings() { EvaluationBudget = settings.EvaluationBudget, RelativePrecision = 0.0, AbsolutePrecision = 0.0 }); //count += f2.Count; //x = f2.Position(mm.Location); x = fo.ComputeLocation(mm.Location); y = mm.Value; // rotate this direction into the direction set /* * for (int i = 0; i < (d - 1); i++) { * Q[i] = Q[i + 1]; * r[i] = r[i + 1]; * } * Q[d - 1] = dx; * r[d - 1] = mm.Curvature; */ // this is the basic Powell procedure, and it leads to linear dependence // replace the direction of largest decrease with the net direction Q[max_i] = dx; r[max_i] = mm.Curvature; if (max_i == 0) { skip = true; } // this is powell's modification to avoid linear dependence // reset } throw new NonconvergenceException(); }
/// <summary> /// Minimizes a function on a multi-dimensional space in the vicinity of a given point, subject to the given settings. /// </summary> /// <param name="f">The function.</param> /// <param name="x">The starting point for the search.</param> /// <param name="settings">The evaluation settings.</param> /// <returns>The minimum.</returns> /// <exception cref="ArgumentNullException"><paramref name="f"/>, <paramref name="x"/>, or <paramref name="settings"/> is null.</exception> /// <exception cref="NonconvergenceException">The minimum was not found to the required precision within the budgeted number of function evaluations.</exception> internal static SpaceExtremum FindMinimum(Func<double[], double> f, double[] x, EvaluationSettings settings) { if (f == null) throw new ArgumentNullException("f"); if (x == null) throw new ArgumentNullException("x"); if (settings == null) throw new ArgumentNullException("settings"); int d = x.Length; // put the function into a Functor we will use for line searches LineSearchFunctor fo = new LineSearchFunctor(f); // keep track of the (conjugate) minimization directions double[][] Q = new double[d][]; for (int i = 0; i < d; i++) { Q[i] = new double[d]; for (int j = 0; j < d; j++) { Q[i][j] = 0.0; } // pick a step size in each direction that represents a fraction of the input value Q[i][i] = (1.0 / 16.0) * (Math.Abs(x[i]) + (1.0 / 16.0)); } // keep track of the curvature in these directions double[] r = new double[d]; // keep track of the function value double y = f(x); // keep track of the total number of evaluations //int count = 0; bool skip = false; // interate until convergence while (fo.EvaluationCount < settings.EvaluationBudget) { // remember our starting position double[] x0 = new double[d]; Array.Copy(x, x0, d); double y0 = y; // keep track of direction of largest decrease double max_dy = 0.0; int max_i = 0; // now minimize in each direction for (int i = 0; i < d; i++) { // if we placed the net direction in the first slot last time, // we are already at the minimum along that direction, so don't // minimize along it if (skip) { skip = false; continue; } //if ((n > 0) && (i == 0) && (max_i == 0)) continue; //Console.WriteLine("i = {0}", i); //WriteVector(Q[i]); // form a line function //LineFunction f1 = new LineFunction(f, x, Q[i]); fo.Origin = x; fo.Direction = Q[i]; // minimize it Extremum m = FindMinimum(fo, 0.0, y, 1.0, new EvaluationSettings() { EvaluationBudget = settings.EvaluationBudget, AbsolutePrecision = 0.0, RelativePrecision = 0.0 }); //LineExtremum m = FindMinimum(new Func<double,double>(f1.Evaluate), 0.0, y, 1.0); // add to the evaluation count //count += f1.Count; // update the current position x = fo.ComputeLocation(m.Location); //x = f1.Position(m.Location); //WriteVector(x); r[i] = m.Curvature; // keep track of how much the function dropped, and // if this is the direction of largest decrease double dy = y - m.Value; //Console.WriteLine("dy = {0}", dy); if (dy > max_dy) { max_dy = dy; max_i = i; } y = m.Value; } //Console.WriteLine("max_i = {0}, max_dy = {1}", max_i, max_dy); //Console.WriteLine("y0 = {0}, y = {1}", y0, y); // figure out the net direction we have moved double[] dx = new double[d]; for (int i = 0; i < d; i++) { dx[i] = x[i] - x0[i]; } //Console.WriteLine("Finish:"); //WriteVector(x); //Console.WriteLine("Net direction:"); //WriteVector(dx); // check termination criteria // we do this before minimizing in the net direction because if dx=0 it loops forever double Dy = Math.Abs(y0 - y); if ((Dy < settings.AbsolutePrecision) || (2.0 * Dy < (Math.Abs(y) + Math.Abs(y0)) * settings.RelativePrecision)) { SymmetricMatrix A = ComputeCurvature(f, x); return (new SpaceExtremum(x, y, A)); } // attempt a minimization in the net direction fo.Origin = x; fo.Direction = dx; //LineFunction f2 = new LineFunction(f, x, dx); //LineExtremum mm = FindMinimum(new Func<double,double>(f2.Evaluate), 0.0, y, 1.0); Extremum mm = FindMinimum(fo, 0.0, y, 1.0, new EvaluationSettings() { EvaluationBudget = settings.EvaluationBudget, RelativePrecision = 0.0, AbsolutePrecision = 0.0 }); //count += f2.Count; //x = f2.Position(mm.Location); x = fo.ComputeLocation(mm.Location); y = mm.Value; // rotate this direction into the direction set /* for (int i = 0; i < (d - 1); i++) { Q[i] = Q[i + 1]; r[i] = r[i + 1]; } Q[d - 1] = dx; r[d - 1] = mm.Curvature; */ // this is the basic Powell procedure, and it leads to linear dependence // replace the direction of largest decrease with the net direction Q[max_i] = dx; r[max_i] = mm.Curvature; if (max_i == 0) skip = true; // this is powell's modification to avoid linear dependence // reset } throw new NonconvergenceException(); }