//RegressionResult double runCalculation(SimplexConstant[] consts) { ObjectiveFunctionDelegate objFunc = new ObjectiveFunctionDelegate(minimizeAngle); RegressionResult result = NelderMeadSimplex.Regress(consts, tolerance, maxEvals, objFunc); return(result.Constants[0]); }
/// <summary> /// Test a scaling operation of the high point, and replace it if it is an improvement /// </summary> /// <param name="scaleFactor"></param> /// <param name="errorProfile"></param> /// <param name="vertices"></param> /// <param name="errorValues"></param> /// <returns></returns> private static double _tryToScaleSimplex(double scaleFactor, ref ErrorProfile errorProfile, Vector[] vertices, double[] errorValues, ObjectiveFunctionDelegate objectiveFunction) { // find the centroid through which we will reflect Vector centroid = _computeCentroid(vertices, errorProfile); // define the vector from the centroid to the high point Vector centroidToHighPoint = vertices[errorProfile.HighestIndex].Subtract(centroid); // scale and position the vector to determine the new trial point Vector newPoint = centroidToHighPoint.Multiply(scaleFactor).Add(centroid); //TODO: should see if this is a good point by constraints, otherwise throw it out // evaluate the new point double newErrorValue = objectiveFunction(newPoint.Components); // if it's better, replace the old high point if (newErrorValue < errorValues[errorProfile.HighestIndex]) { vertices[errorProfile.HighestIndex] = newPoint; errorValues[errorProfile.HighestIndex] = newErrorValue; } return(newErrorValue); }
public HybridACOGA(int numberOfVariables, OptimizationType opType, GA <int> .ObjectiveFunctionDelegate objectFunction, double[,] distance) : base(numberOfVariables, opType, objectFunction) { getObjectiveValue = objectFunction; numberOfCity = numberOfVariables; FromToDistanceMatrix = distance; // Allocate memory for pheromone matrix and heuristic value matrix // Heuristic values in the matrix are computed and assigned via // the specified function delegate pheromone = new double[numberOfCity, numberOfCity]; indicesOfAnts = new int[populationSize]; solutions = new int[populationSize][]; soFarTheBestSoluiton = new int[numberOfCity]; for (int r = 0; r < numberOfCity; r++) { for (int c = 0; c < numberOfCity; c++) { pheromone[r, c] = 0.01; } } for (int r = 0; r < numberOfCity; r++) { for (int c = 0; c < numberOfCity; c++) { AverageDistance += FromToDistanceMatrix[r, c]; } } AverageDistance = AverageDistance / (numberOfCity * numberOfCity); heuristicValues = new double[numberOfCity, numberOfCity]; for (int r = 0; r < numberOfCity; r++) { for (int c = 0; c < numberOfCity; c++) { heuristicValues[r, c] = DistanceInverseHeuristic(r, c); } } for (int i = 0; i < populationSize; i++) { indicesOfAnts[i] = i; solutions[i] = new int[numberOfCity]; for (int j = 0; j < numberOfCity; j++) { solutions[i][j] = j; } KnuthShuffle(solutions[i]); } // Allocate memory for the arries used in ACO, whose length is // depend on the number of variables. In contrast, those arraies // with length depending on the number of ants are allocated in // reset function. probabilities = new double[numberOfCity]; candidateSet = new int[numberOfCity]; ObjectiveValues = new double[populationSize]; // Set drop amount multiplier; which is the avarage length //dropMultiplier = dropPheromone * dropMultiplier / getObjectiveValue(objectiveValues); }
/// <summary> /// Evaluate the objective function at each vertex to create a corresponding /// list of error values for each vertex /// </summary> private static double[] InitializeErrorValues(Vector <double>[] vertices, ObjectiveFunctionDelegate objectiveFunction) { double[] errorValues = new double[vertices.Length]; for (int i = 0; i < vertices.Length; i++) { errorValues[i] = objectiveFunction(vertices[i].ToArray()); } return(errorValues); }
/// <summary> /// Evaluate the objective function at each vertex to create a corresponding /// list of error values for each vertex /// </summary> /// <param name="vertices"></param> /// <returns></returns> private static double[] _initializeErrorValues(Vector[] vertices, ObjectiveFunctionDelegate objectiveFunction) { double[] errorValues = new double[vertices.Length]; for (int i = 0; i < vertices.Length; i++) { errorValues[i] = objectiveFunction(vertices[i].Components); } return(errorValues); }
/// <summary> /// Test to see if we can fit a parabola /// </summary> public static void SimplexTest1() { Console.WriteLine("Starting SimplexTest1"); SimplexConstant[] constants = new SimplexConstant[] { new SimplexConstant(3, 1), new SimplexConstant(5, 1) }; double tolerance = 1e-6; int maxEvals = 1000; ObjectiveFunctionDelegate objFunction = new ObjectiveFunctionDelegate(_objFunction1); RegressionResult result = NelderMeadSimplex.Regress(constants, tolerance, maxEvals, objFunction); _printResult(result); }
/// <summary> /// Test to see if we can fit a parabola /// </summary> public static void SimplexTest1() { Console.WriteLine("Starting SimplexTest1"); SimplexConstant[] constants = new SimplexConstant[] { new SimplexConstant(3, 1), new SimplexConstant(5, 1) }; double tolerance = 1e-6; int maxEvals = 1000; ObjectiveFunctionDelegate objFunction = new ObjectiveFunctionDelegate(_objFunction1); RegressionResult result = NelderMeadSimplex.Regress(constants, tolerance, maxEvals, objFunction); _printResult(result); }
/// <summary> /// To employ a GA solver, user must provide the number of variables, the optimization type, and a function delegate /// that compute and return the objective value for a given solution. /// </summary> /// <param name="numberOfVariables"> Number of variables of the problem</param> /// <param name="opType"> The optimization problem type </param> /// <param name="objectFunction"> The function delegate that computer the objective value for a given solution </param> public GA(int numberOfVariables, OptimizationType opType, GA <T> .ObjectiveFunctionDelegate objectFunction) { numberOfGenes = numberOfVariables; optimizationType = opType; if (objectFunction == null) { throw new Exception("You must prepare an objective function."); } GetObjectiveValueFunction = objectFunction; }
/// <summary> /// Test on the Rosenbrock function /// </summary> public static void SimplexTest2() { Console.WriteLine("\n\nStarting SimplexTest2"); // we are regressing for frequency, amplitude, and phase offset SimplexConstant[] constants = new SimplexConstant[] { new SimplexConstant(-1.2, .1), new SimplexConstant(1, .1)}; double tolerance = 1e-10; int maxEvals = 1000; ObjectiveFunctionDelegate objFunction = new ObjectiveFunctionDelegate(_objFunction2); RegressionResult result = NelderMeadSimplex.Regress(constants, tolerance, maxEvals, objFunction); _printResult(result); }
/// <summary> /// Test on the Rosenbrock function /// </summary> public static void SimplexTest2() { Console.WriteLine("\n\nStarting SimplexTest2"); // we are regressing for frequency, amplitude, and phase offset SimplexConstant[] constants = new SimplexConstant[] { new SimplexConstant(-1.2, .1), new SimplexConstant(1, .1)}; double tolerance = 1e-10; int maxEvals = 1000; ObjectiveFunctionDelegate objFunction = new ObjectiveFunctionDelegate(_objFunction2); RegressionResult result = NelderMeadSimplex.Regress(constants, tolerance, maxEvals, objFunction); _printResult(result); }
/// <summary> /// Test to see if we can fit a parabola /// </summary> private static void _simplexTest1() { Console.WriteLine("Starting SimplexTest1"); SimplexConstant[] nss = new SimplexConstant[] { new SimplexConstant(0, 1), new SimplexConstant(0, 1), new SimplexConstant(0, 1), new SimplexConstant(0, 1), new SimplexConstant(1, 1), new SimplexConstant(1, 1) }; double[] tt = { 5.0, 10.0, 15.0, 20.0, 25.0 }; double[] Y = { 0.001770949, 0.008396027, 0.013860686, 0.019379306, 0.023731833 }; double tolerance = 1e-6; int maxEvals = 1000; ObjectiveFunctionDelegate objFunction = new ObjectiveFunctionDelegate(_objFunction1); RegressionResult result = NelderMeadSimplex.Regress(nss, tt, Y, tolerance, maxEvals, objFunction); _printResult(result); }
/// <summary> /// Contract the simplex uniformly around the lowest point /// </summary> private static void ShrinkSimplex(ErrorProfile errorProfile, Vector <double>[] vertices, double[] errorValues, ObjectiveFunctionDelegate objectiveFunction) { Vector <double> lowestVertex = vertices[errorProfile.LowestIndex]; for (int i = 0; i < vertices.Length; i++) { if (i != errorProfile.LowestIndex) { vertices[i] = (vertices[i].Add(lowestVertex)).Multiply(0.5); errorValues[i] = objectiveFunction(vertices[i].ToArray()); } } }
/// <summary> /// Contract the simplex uniformly around the lowest point /// </summary> /// <param name="errorProfile"></param> /// <param name="vertices"></param> /// <param name="errorValues"></param> private static void _shrinkSimplex(ErrorProfile errorProfile, Vector[] vertices, double[] errorValues, ObjectiveFunctionDelegate objectiveFunction, double[] tt, double[] Y) { Vector lowestVertex = vertices[errorProfile.LowestIndex]; for (int i = 0; i < vertices.Length; i++) { if (i != errorProfile.LowestIndex) { vertices[i] = (vertices[i].Add(lowestVertex)).Multiply(0.5); errorValues[i] = objectiveFunction(vertices[i].Components, tt, Y); } } }
// Run cost minimization Vector3 IDecisionManager.getNextDesiredPoint() { // What are the variables to minimize (position) SimplexConstant[] constants = new SimplexConstant[] { new SimplexConstant(this.sensorModule.gps.position.x, 1), new SimplexConstant(this.sensorModule.gps.position.y, 1), new SimplexConstant(this.sensorModule.gps.position.z, 1) }; double tolerance = 1e-30; int maxEvals = 10000; // What's the objective function ObjectiveFunctionDelegate objFunction = new ObjectiveFunctionDelegate(_objFunction1); RegressionResult result = NelderMeadSimplex.Regress(constants, tolerance, maxEvals, objFunction); Vector3 r = new Vector3((float)result.Constants[0], (float)result.Constants[1], (float)result.Constants[2]); // Debug.Log (result.TerminationReason.ToString ()); return(r); }
public void Minimize() { SetCoefficients(); Console.WriteLine("Starting minimization..."); SimplexConstant[] constants = new SimplexConstant[Coefficients.Length]; for (int i = 0; i < Coefficients.Length; i++) { constants[i] = new SimplexConstant(Coefficients[i], Math.Abs(Coefficients[i]) / 2); } double tolerance = 1e-6; int maxEvals = 1000; ObjectiveFunctionDelegate objFunction = new ObjectiveFunctionDelegate(SpiderObjectiveFunction); RegressionResult result = NelderMeadSimplex.Regress(constants, tolerance, maxEvals, objFunction); Coefficients = result.Constants; PrintCoefficients(Coefficients); }
public void Initialize(ObjectiveFunctionDelegate _ofd, int _total, double[] _scale, bool[] _fixt) { ofd = _ofd; total = _total; accepted = 0; dim = _scale.Length; Scale = _scale; searchRadius = 1.0 / Scale.Length; this.IntializeScale(searchRadius, _fixt); // uniform on [0,1] uRand.Alpha = 0.0; uRand.Beta = 1.0; // standard gaussian parameters zRand.Mu = 0; zRand.Sigma = 1; Temperature = 1; }
/// <summary> /// Test a scaling operation of the high point, and replace it if it is an improvement /// </summary> private static double TryToScaleSimplex(double scaleFactor, ref ErrorProfile errorProfile, Vector <double>[] vertices, double[] errorValues, ObjectiveFunctionDelegate objectiveFunction) { // find the centroid through which we will reflect Vector centroid = ComputeCentroid(vertices, errorProfile); // define the vector from the centroid to the high point Vector centroidToHighPoint = (Vector)vertices[errorProfile.HighestIndex].Subtract(centroid); // scale and position the vector to determine the new trial point Vector newPoint = (Vector)centroidToHighPoint.Multiply(scaleFactor).Add(centroid); // evaluate the new point double newErrorValue = objectiveFunction(newPoint.ToArray()); // if it's better, replace the old high point if (newErrorValue < errorValues[errorProfile.HighestIndex]) { vertices[errorProfile.HighestIndex] = newPoint; errorValues[errorProfile.HighestIndex] = newErrorValue; } return(newErrorValue); }
public void Minimize() { SetCoefficients(); Console.WriteLine("Starting minimization..."); SimplexConstant[] constants = new SimplexConstant[Coefficients.Length]; for (int i = 0; i < Coefficients.Length; i++) { constants[i] = new SimplexConstant(Coefficients[i], Math.Abs(Coefficients[i]) / 2); } double tolerance = 1e-6; int maxEvals = 1000; ObjectiveFunctionDelegate objFunction = new ObjectiveFunctionDelegate(SpiderObjectiveFunction); RegressionResult result = NelderMeadSimplex.Regress(constants, tolerance, maxEvals, objFunction); Coefficients = result.Constants; PrintCoefficients(Coefficients); }
private const double JITTER = 1e-10d; // a small value used to protect against floating point noise #endregion Fields #region Methods public static RegressionResult Regress(SimplexConstant[] simplexConstants, double convergenceTolerance, int maxEvaluations, ObjectiveFunctionDelegate objectiveFunction) { // confirm that we are in a position to commence if (objectiveFunction == null) throw new InvalidOperationException("ObjectiveFunction must be set to a valid ObjectiveFunctionDelegate"); if (simplexConstants == null) throw new InvalidOperationException("SimplexConstants must be initialized"); // create the initial simplex int numDimensions = simplexConstants.Length; int numVertices = numDimensions + 1; Vector[] vertices = _initializeVertices(simplexConstants); int evaluationCount = 0; TerminationReason terminationReason; ErrorProfile errorProfile; double[] errorValues = _initializeErrorValues(vertices, objectiveFunction); // iterate until we converge, or complete our permitted number of iterations while (true) { errorProfile = _evaluateSimplex(errorValues); // see if the range in point heights is small enough to exit if (_hasConverged(convergenceTolerance, errorProfile, errorValues)) { terminationReason = TerminationReason.Converged; break; } // attempt a reflection of the simplex double reflectionPointValue = _tryToScaleSimplex(-1.0, ref errorProfile, vertices, errorValues, objectiveFunction); ++evaluationCount; if (reflectionPointValue <= errorValues[errorProfile.LowestIndex]) { // it's better than the best point, so attempt an expansion of the simplex double expansionPointValue = _tryToScaleSimplex(2.0, ref errorProfile, vertices, errorValues, objectiveFunction); ++evaluationCount; } else if (reflectionPointValue >= errorValues[errorProfile.NextHighestIndex]) { // it would be worse than the second best point, so attempt a contraction to look // for an intermediate point double currentWorst = errorValues[errorProfile.HighestIndex]; double contractionPointValue = _tryToScaleSimplex(0.5, ref errorProfile, vertices, errorValues, objectiveFunction); ++evaluationCount; if (contractionPointValue >= currentWorst) { // that would be even worse, so let's try to contract uniformly towards the low point; // don't bother to update the error profile, we'll do it at the start of the // next iteration _shrinkSimplex(errorProfile, vertices, errorValues, objectiveFunction); evaluationCount += numVertices; // that required one function evaluation for each vertex; keep track } } // check to see if we have exceeded our alloted number of evaluations if (evaluationCount >= maxEvaluations) { terminationReason = TerminationReason.MaxFunctionEvaluations; break; } } var regressionResult = new RegressionResult(terminationReason, vertices[errorProfile.LowestIndex].Components, errorValues[errorProfile.LowestIndex], evaluationCount); return regressionResult; }
/// <summary> /// Evaluate the objective function at each vertex to create a corresponding /// list of error values for each vertex /// </summary> /// <param name="vertices"></param> /// <param name="objectiveFunction"></param> /// <returns></returns> private static double[] _initializeErrorValues(Vector[] vertices, ObjectiveFunctionDelegate objectiveFunction) { var errorValues = new double[vertices.Length]; for (int i = 0; i < vertices.Length; i++) { errorValues[i] = objectiveFunction(vertices[i].Components); } return errorValues; }
public double FindFit(double[] _pmin, double[] _start, double _delta, double _tolerance, int _maxIterations, ObjectiveFunctionDelegate _objectiveFn) { // initialise simplex Mov(s[0], _start); for (int i = 1; i < NB_POINTS; i++) { Mov(s[i], _start); s[i][i - 1] += _delta; } // evaluate function at each point on simplex for (int i = 0; i < NB_POINTS; i++) { f[i] = _objectiveFn(s[i]); } double[] o = new double[DIM]; // Centroid double[] r = new double[DIM]; // Reflection double[] c = new double[DIM]; // Contraction double[] e = new double[DIM]; // Expansion int lo = 0, hi, nh; for (m_lastIterationsCount = 0; m_lastIterationsCount < _maxIterations; m_lastIterationsCount++) { // find lowest, highest and next highest lo = hi = nh = 0; for (int i = 1; i < NB_POINTS; i++) { if (f[i] < f[lo]) { lo = i; } if (f[i] > f[hi]) { nh = hi; hi = i; } else if (f[i] > f[nh]) { nh = i; } } // stop if we've reached the required tolerance level double a = Math.Abs(f[lo]); double b = Math.Abs(f[hi]); if (2.0 * Math.Abs(a - b) < (a + b) * _tolerance) { break; } // compute centroid (excluding the worst point) Set(o, 0.0f); for (int i = 0; i < NB_POINTS; i++) { if (i == hi) { continue; } Add(o, s[i]); } for (int i = 0; i < DIM; i++) { o[i] /= DIM; } // reflection for (int i = 0; i < DIM; i++) { r[i] = o[i] + reflect * (o[i] - s[hi][i]); } double fr = _objectiveFn(r); if (fr < f[nh]) { if (fr < f[lo]) { // expansion for (int i = 0; i < DIM; i++) { e[i] = o[i] + expand * (o[i] - s[hi][i]); } double fe = _objectiveFn(e); if (fe < fr) { Mov(s[hi], e); f[hi] = fe; continue; } } Mov(s[hi], r); f[hi] = fr; continue; } // contraction for (int i = 0; i < DIM; i++) { c[i] = o[i] - contract * (o[i] - s[hi][i]); } double fc = _objectiveFn(c); if (fc < f[hi]) { Mov(s[hi], c); f[hi] = fc; continue; } // reduction for (int k = 0; k < NB_POINTS; k++) { if (k == lo) { continue; } for (int i = 0; i < DIM; i++) { s[k][i] = s[lo][i] + shrink * (s[k][i] - s[lo][i]); } f[k] = _objectiveFn(s[k]); } } // return best point and its value Mov(_pmin, s[lo]); return(f[lo]); }
/// <summary> /// Evaluate the objective function at each vertex to create a corresponding /// list of error values for each vertex /// </summary> /// <param name="vertices"></param> /// <returns></returns> private static double[] _initializeErrorValues(Vector[] vertices, ObjectiveFunctionDelegate objectiveFunction) { double[] errorValues = new double[vertices.Length]; for (int i = 0; i < vertices.Length; i++) { errorValues[i] = objectiveFunction(vertices[i].Components); #if DEBUG Console.Write(i + ":" + vertices[i]+"=="); #endif } return errorValues; }
/// <summary> /// Contract the simplex uniformly around the lowest point /// </summary> /// <param name="errorProfile"></param> /// <param name="vertices"></param> /// <param name="errorValues"></param> private static void _shrinkSimplex(ErrorProfile errorProfile, Vector[] vertices, double[] errorValues, ObjectiveFunctionDelegate objectiveFunction) { Vector lowestVertex = vertices[errorProfile.LowestIndex]; for (int i = 0; i < vertices.Length; i++) { if (i != errorProfile.LowestIndex) { vertices[i] = (vertices[i].Add(lowestVertex)).Multiply(0.5); errorValues[i] = objectiveFunction(vertices[i].Components); } } }
private const double JITTER = 1e-10d; // a small value used to protect against floating point noise public static RegressionResult Regress(SimplexConstant[] simplexConstants, double convergenceTolerance, int maxEvaluations, ObjectiveFunctionDelegate objectiveFunction) { // confirm that we are in a position to commence if (objectiveFunction == null) { throw new InvalidOperationException("ObjectiveFunction must be set to a valid ObjectiveFunctionDelegate"); // Not L10N } if (simplexConstants == null) { throw new InvalidOperationException("SimplexConstants must be initialized"); // Not L10N } // create the initial simplex int numDimensions = simplexConstants.Length; int numVertices = numDimensions + 1; Vector <double>[] vertices = InitializeVertices(simplexConstants); int evaluationCount = 0; TerminationReason terminationReason; ErrorProfile errorProfile; double[] errorValues = InitializeErrorValues(vertices, objectiveFunction); // iterate until we converge, or complete our permitted number of iterations while (true) { errorProfile = EvaluateSimplex(errorValues); // see if the range in point heights is small enough to exit if (HasConverged(convergenceTolerance, errorProfile, errorValues)) { terminationReason = TerminationReason.Converged; break; } // attempt a reflection of the simplex double reflectionPointValue = TryToScaleSimplex(-1.0, ref errorProfile, vertices, errorValues, objectiveFunction); ++evaluationCount; if (reflectionPointValue <= errorValues[errorProfile.LowestIndex]) { // it's better than the best point, so attempt an expansion of the simplex TryToScaleSimplex(2.0, ref errorProfile, vertices, errorValues, objectiveFunction); ++evaluationCount; } else if (reflectionPointValue >= errorValues[errorProfile.NextHighestIndex]) { // it would be worse than the second best point, so attempt a contraction to look // for an intermediate point double currentWorst = errorValues[errorProfile.HighestIndex]; double contractionPointValue = TryToScaleSimplex(0.5, ref errorProfile, vertices, errorValues, objectiveFunction); ++evaluationCount; if (contractionPointValue >= currentWorst) { // that would be even worse, so let's try to contract uniformly towards the low point; // don't bother to update the error profile, we'll do it at the start of the // next iteration ShrinkSimplex(errorProfile, vertices, errorValues, objectiveFunction); evaluationCount += numVertices; // that required one function evaluation for each vertex; keep track } } // check to see if we have exceeded our alloted number of evaluations if (evaluationCount >= maxEvaluations) { terminationReason = TerminationReason.MaxFunctionEvaluations; break; } } RegressionResult regressionResult = new RegressionResult(terminationReason, vertices[errorProfile.LowestIndex].ToArray(), errorValues[errorProfile.LowestIndex], evaluationCount); return(regressionResult); }
/// <summary> /// Evaluate the objective function at each vertex to create a corresponding /// list of error values for each vertex /// </summary> private static double[] InitializeErrorValues(Vector<double>[] vertices, ObjectiveFunctionDelegate objectiveFunction) { double[] errorValues = new double[vertices.Length]; for (int i = 0; i < vertices.Length; i++) { errorValues[i] = objectiveFunction(vertices[i].ToArray()); } return errorValues; }
private static readonly double JITTER = 1e-10d; // a small value used to protect against floating point noise #endregion Fields #region Methods public static RegressionResult Regress(SimplexConstant[] simplexConstants, double convergenceTolerance, int maxEvaluations, ObjectiveFunctionDelegate objectiveFunction) { // confirm that we are in a position to commence if (objectiveFunction == null) throw new InvalidOperationException("ObjectiveFunction must be set to a valid ObjectiveFunctionDelegate"); if (simplexConstants == null) throw new InvalidOperationException("SimplexConstants must be initialized"); #if DEBUG //this is the coniditional compilation symbols in the project property >>build section Console.Write("inside nelder mead regression:"); #endif // create the initial simplex int numDimensions = simplexConstants.Length; int numVertices = numDimensions + 1; #if DEBUG Console.Write("numVertices: {0}", numVertices ); #endif Vector[] vertices = _initializeVertices(simplexConstants); double[] errorValues = new double[numVertices]; int evaluationCount = 0; TerminationReason terminationReason = TerminationReason.Unspecified; ErrorProfile errorProfile; errorValues = _initializeErrorValues(vertices, objectiveFunction); #if DEBUG || LOG_MODE Console.WriteLine("\n=====Start the Nelder-Mead Algorithm for Optimization.........."); #endif // iterate until we converge, or complete our permitted number of iterations while (true) { #if LOG_MODE if (evaluationCount % 100 == 0) { Console.Write("......"+evaluationCount+ "/"+maxEvaluations ); } #endif errorProfile = _evaluateSimplex(errorValues); // see if the range in point heights is small enough to exit if (_hasConverged(convergenceTolerance, errorProfile, errorValues)) { terminationReason = TerminationReason.Converged; break; } #if DEBUG Console.WriteLine("not converged"); #endif // attempt a reflection of the simplex double reflectionPointValue = _tryToScaleSimplex(-1.0, ref errorProfile, vertices, errorValues, objectiveFunction); ++evaluationCount; #if DEBUG Console.WriteLine("Got a reflection point"); #endif if (reflectionPointValue <= errorValues[errorProfile.LowestIndex]) { // it's better than the best point, so attempt an expansion of the simplex double expansionPointValue = _tryToScaleSimplex(2.0, ref errorProfile, vertices, errorValues, objectiveFunction); ++evaluationCount; } else if (reflectionPointValue >= errorValues[errorProfile.NextHighestIndex]) { // it would be worse than the second best point, so attempt a contraction to look // for an intermediate point double currentWorst = errorValues[errorProfile.HighestIndex]; double contractionPointValue = _tryToScaleSimplex(0.5, ref errorProfile, vertices, errorValues, objectiveFunction); ++evaluationCount; if (contractionPointValue >= currentWorst) { // that would be even worse, so let's try to contract uniformly towards the low point; // don't bother to update the error profile, we'll do it at the start of the // next iteration _shrinkSimplex(errorProfile, vertices, errorValues, objectiveFunction); evaluationCount += numVertices; // that required one function evaluation for each vertex; keep track } } // check to see if we have exceeded our alloted number of evaluations if (evaluationCount >= maxEvaluations) { terminationReason = TerminationReason.MaxFunctionEvaluations; break; } } #if LOG_MODE Console.WriteLine("Done!!"); #endif RegressionResult regressionResult = new RegressionResult(terminationReason, vertices[errorProfile.LowestIndex].Components, errorValues[errorProfile.LowestIndex], evaluationCount); return regressionResult; }
/// <summary> /// Test a scaling operation of the high point, and replace it if it is an improvement /// </summary> private static double TryToScaleSimplex(double scaleFactor, ref ErrorProfile errorProfile, Vector<double>[] vertices, double[] errorValues, ObjectiveFunctionDelegate objectiveFunction) { // find the centroid through which we will reflect Vector centroid = ComputeCentroid(vertices, errorProfile); // define the vector from the centroid to the high point Vector centroidToHighPoint = (Vector) vertices[errorProfile.HighestIndex].Subtract(centroid); // scale and position the vector to determine the new trial point Vector newPoint = (Vector) centroidToHighPoint.Multiply(scaleFactor).Add(centroid); // evaluate the new point double newErrorValue = objectiveFunction(newPoint.ToArray()); // if it's better, replace the old high point if (newErrorValue < errorValues[errorProfile.HighestIndex]) { vertices[errorProfile.HighestIndex] = newPoint; errorValues[errorProfile.HighestIndex] = newErrorValue; } return newErrorValue; }
/// <summary> /// Test a scaling operation of the high point, and replace it if it is an improvement /// </summary> /// <param name="scaleFactor"></param> /// <param name="errorProfile"></param> /// <param name="vertices"></param> /// <param name="errorValues"></param> /// <returns></returns> private static double _tryToScaleSimplex(double scaleFactor, ref ErrorProfile errorProfile, Vector[] vertices, double[] errorValues, ObjectiveFunctionDelegate objectiveFunction) { // find the centroid through which we will reflect Vector centroid = _computeCentroid(vertices, errorProfile); #if DEBUG Console.WriteLine("centroid:" + centroid.ToString()); #endif // define the vector from the centroid to the high point Vector centroidToHighPoint = vertices[errorProfile.HighestIndex].Subtract(centroid); // scale and position the vector to determine the new trial point Vector newPoint = centroidToHighPoint.Multiply(scaleFactor).Add(centroid); // evaluate the new point double newErrorValue = objectiveFunction(newPoint.Components); // if it's better, replace the old high point if (newErrorValue < errorValues[errorProfile.HighestIndex]) { vertices[errorProfile.HighestIndex] = newPoint; errorValues[errorProfile.HighestIndex] = newErrorValue; } return newErrorValue; }
//public System.IO.StreamWriter log = new System.IO.FileInfo( "log.txt" ).CreateText(); public double FindFit(double[] _pmin, double[] _start, double _delta, double _tolerance, int _maxIterations, ObjectiveFunctionDelegate _objectiveFn) { // initialise simplex Mov(s[0], _start); for (int i = 1; i < NB_POINTS; i++) { Mov(s[i], _start); s[i][i - 1] += _delta; } // evaluate function at each point on simplex //log.WriteLine( "Init" ); for (int i = 0; i < NB_POINTS; i++) { f[i] = _objectiveFn(s[i]); //log.WriteLine( "f[{0}] = {1}", i, f[i] ); } // if ( f[0] < _tolerance ) { // // Already at a minimum! // Mov( _pmin, _start ); // return f[0]; // } double[] o = new double[DIM]; // Centroid double[] r = new double[DIM]; // Reflection double[] c = new double[DIM]; // Contraction double[] e = new double[DIM]; // Expansion int lo = 0, hi, nh; for (m_lastIterationsCount = 0; m_lastIterationsCount < _maxIterations; m_lastIterationsCount++) { //log.WriteLine(); //log.WriteLine( "===================================" ); //log.WriteLine( "Iteration #" + m_lastIterationsCount ); // find lowest, highest and next highest lo = hi = nh = 0; for (int i = 1; i < NB_POINTS; i++) { if (f[i] < f[lo]) { lo = i; } if (f[i] > f[hi]) { nh = hi; hi = i; } else if (f[i] > f[nh]) { nh = i; } //log.WriteLine( "f[{0}] = {1}", i, f[i] ); } // stop if we've reached the required tolerance level double a = Mathf.Abs(f[lo]); double b = Mathf.Abs(f[hi]); if (2.0 * Mathf.Abs(a - b) < (a + b) * _tolerance) // || a + b == 0.0 ) { break; } // compute centroid (excluding the worst point) Set(o, 0.0f); for (int i = 0; i < NB_POINTS; i++) { if (i == hi) { continue; } Add(o, s[i]); } for (int i = 0; i < DIM; i++) { o[i] /= DIM; } //log.WriteLine( "centroid = {{ {0}, {1}, {2} }}", o[0], o[1], o[2] ); // reflection for (int i = 0; i < DIM; i++) { r[i] = o[i] + reflect * (o[i] - s[hi][i]); } double fr = _objectiveFn(r); //log.WriteLine( "reflection = {{ {0}, {1}, {2} }}", r[0], r[1], r[2] ); //log.WriteLine( "reflection error = " + fr ); if (fr < f[nh]) { if (fr < f[lo]) { // expansion for (int i = 0; i < DIM; i++) { e[i] = o[i] + expand * (o[i] - s[hi][i]); } double fe = _objectiveFn(e); //log.WriteLine( "expansion = {{ {0}, {1}, {2} }}", e[0], e[1], e[2] ); //log.WriteLine( "expansion error = " + fe ); if (fe < fr) { Mov(s[hi], e); f[hi] = fe; //log.WriteLine( "CHOSE EXPANSION" ); continue; } } Mov(s[hi], r); f[hi] = fr; //log.WriteLine( "CHOSE REFLECTION" ); continue; } // contraction for (int i = 0; i < DIM; i++) { c[i] = o[i] - contract * (o[i] - s[hi][i]); } double fc = _objectiveFn(c); //log.WriteLine( "contraction = {{ {0}, {1}, {2} }}", c[0], c[1], c[2] ); //log.WriteLine( "contraction error = " + fc ); if (fc < f[hi]) { Mov(s[hi], c); f[hi] = fc; //log.WriteLine( "CHOSE CONTRACTION" ); continue; } // reduction for (int k = 0; k < NB_POINTS; k++) { if (k == lo) { continue; } for (int i = 0; i < DIM; i++) { s[k][i] = s[lo][i] + shrink * (s[k][i] - s[lo][i]); } f[k] = _objectiveFn(s[k]); } //log.WriteLine( "CHOSE REDUCTION" ); } // return best point and its value Mov(_pmin, s[lo]); // log.WriteLine(); // log.WriteLine(); // log.WriteLine( "===================================" ); // log.WriteLine( "Exiting after " + m_lastIterationsCount + " iterations" ); // log.WriteLine( "Result = {{ {0}, {1}, {2} }}", _pmin[0], _pmin[1], _pmin[2] ); // log.WriteLine( "Error = " + f[lo] ); return(f[lo]); }