/// <summary> /// Finds the minimum of the function. /// </summary> /// <param name="f">the function to be minimized.</param> /// <param name="maxiterations">ignored.</param> /// <returns>the minimum of the function.</returns> /// <remarks>The function domain must be bounded on all parameters.</remarks> public double[] FindMinimum(ITargetFunction f, int maxiterations) { int i, j; int par = f.CountParams; double [] mins = new double[par]; double [] maxs = new double[par]; int [] steps = new int[par]; double [][] gridpoints = new double [par][]; for (i = 0; i < par; i++) { mins[i] = f.RangeMin(i); maxs[i] = f.RangeMax(i); if (double.IsInfinity(mins[i]) || double.IsInfinity(maxs[i])) { throw new MinimizationException("Function domain is unbounded on parameter #" + i + "."); } if (maxs[i] < mins[i]) { throw new MinimizationException("Null domain on parameter #" + i + "."); } steps[i] = (int)(1 + Math.Floor((maxs[i] - mins[i]) / GridSteps[i])); gridpoints[i] = new double[steps[i]]; for (j = 0; j < steps[i]; j++) { gridpoints[i][j] = Math.Min(mins[i] + j * GridSteps[i], maxs[i]); } } double fmin = f.Evaluate(mins); int[] iiib = new int[par]; int[] iiis = new int[par]; double v; double[] x = new double[par]; if (m_TW != null) { m_TW.WriteLine("Start RangeScan"); } while (true) { for (i = 0; i < par && ++iiis[i] == steps[i]; i++) { iiis[i] = 0; } if (i == par) { break; } for (i = 0; i < par; i++) { x[i] = gridpoints[i][iiis[i]]; } v = f.Evaluate(x); if (m_TW != null) { for (i = 0; i < par; i++) { m_TW.Write(x[i] + " "); } m_TW.WriteLine(v); } if (v < fmin) { fmin = v; for (i = 0; i < par; i++) { iiib[i] = iiis[i]; } } } for (i = 0; i < par; i++) { x[i] = gridpoints[i][iiib[i]]; } m_Point = x; m_Value = fmin; if (m_TW != null) { m_TW.WriteLine("Minimum"); for (i = 0; i < par; i++) { m_TW.Write(x[i] + " "); } m_TW.WriteLine(fmin); m_TW.WriteLine("End RangeScan"); } return(x); }
/// <summary> /// Finds a local minimum for the function using Newton's algorithm. /// </summary> /// <param name="f">the function to be minimized.</param> /// <param name="maxiterations">the maximum number of iterations to try. Set to a non-positive number to allow infinite iterations.</param> /// <returns>the location of the local minimum.</returns> /// <remarks>The complete Hessian must be available through function derivation.</remarks> public double[] FindMinimum(ITargetFunction f, int maxiterations) { int par = f.CountParams; ITargetFunction[] grad = new ITargetFunction[par]; ITargetFunction[,] hessian = new ITargetFunction[par, par]; int i, j; double [] xstart = f.Start; double [] x = new double[par]; double [] xn = new double[par]; double [] dx = new double[par]; double dxnorm; double [] mins = new double[par]; double [] maxs = new double[par]; for (i = 0; i < par; i++) { x[i] = xstart[i]; mins[i] = f.RangeMin(i); maxs[i] = f.RangeMax(i); if (x[i] < mins[i] || x[i] > maxs[i]) { throw new MinimizationException("Starting point is out of bounds."); } } double f1 = f.Evaluate(x); double f2 = f1; double[] g = new double[par]; double[,] h = new double[par, par]; double[][] hi = null; for (i = 0; i < par; i++) { try { grad[i] = f.Derive(i); } catch (Exception ex) { throw new MinimizationException("The partial derivative #" + i + " is not available.\r\n" + ex.ToString()); } for (j = i; j < par; j++) { try { hessian[i, j] = grad[i].Derive(j); } catch (Exception ex) { throw new MinimizationException("The second partial derivative #" + i + "," + j + " is not available.\r\n" + ex.ToString()); } hessian[j, i] = hessian[i, j]; } } do { f1 = f2; for (i = 0; i < par; i++) { g[i] = grad[i].Evaluate(x); for (j = i; j < par; j++) { h[j, i] = h[i, j] = hessian[i, j].Evaluate(x); } } if (m_TW != null) { m_TW.WriteLine("Remaining iterations: " + maxiterations); m_TW.Write("X ="); for (i = 0; i < par; i++) { m_TW.Write(" " + x[i]); } m_TW.WriteLine(); m_TW.WriteLine("F = " + f1); m_TW.Write("G = "); for (i = 0; i < par; i++) { m_TW.Write(" " + g[i]); } m_TW.WriteLine(); m_TW.WriteLine("H = "); for (i = 0; i < par; i++) { for (j = 0; j < par; j++) { m_TW.Write(" " + h[i, j]); } m_TW.WriteLine(); } } try { hi = new Cholesky(h, 0.0).Inverse(0.0); } catch (Exception ex) { string xs = ""; for (i = 0; i < par; i++) { xs += " " + x[i]; } throw new MinimizationException("Hessian is not positive-definite at" + xs + ".\r\n" + ex.ToString()); } for (i = 0; i < par; i++) { dx[i] = 0.0; for (j = 0; j < par; j++) { dx[i] -= hi[Math.Max(i, j)][Math.Min(i, j)] * g[j]; } dx[i] *= 0.5; } while (true) { for (i = 0; i < par; i++) { xn[i] = x[i] + dx[i]; if (xn[i] < mins[i]) { xn[i] = mins[i]; } else if (xn[i] > maxs[i]) { xn[i] = maxs[i]; } } if (f.Evaluate(xn) <= f1) { break; } else { for (i = 0; i < par; i++) { dx[i] /= 2; } } } for (i = 0; i < par; i++) { dx[i] = xn[i] - x[i]; } dxnorm = 0.0; for (i = 0; i < par; i++) { x[i] = xn[i]; dxnorm += dx[i] * dx[i]; } dxnorm = Math.Sqrt(dxnorm); f2 = f.Evaluate(xn); if (m_TW != null) { m_TW.Write("DX ="); for (i = 0; i < par; i++) { m_TW.Write(" " + dx[i]); } m_TW.WriteLine(); m_TW.WriteLine("DXNORM = " + dxnorm + " FNEW = " + f2 + " FCHANGE = " + (f2 - f1)); } }while (f.StopMinimization(f2, f2 - f1, dxnorm) == false && ((maxiterations <= 0) ? -1 : --maxiterations) != 0); m_Value = f2; m_Point = x; return(m_Point); }