/// <summary> /// Multiply this vector by a scalar value /// </summary> /// <param name="scalar"></param> /// <returns></returns> public Vector Multiply(double scalar) { Vector scaledVector = new Vector(this.NDimensions); for (int i = 0; i < this.NDimensions; i++) { scaledVector[i] = this[i] * scalar; } return scaledVector; }
/// <summary> /// Subtract another vector from this one /// </summary> /// <param name="v"></param> /// <returns></returns> public Vector Subtract(Vector v) { if (v.NDimensions != this.NDimensions) throw new ArgumentException("Can only subtract vectors of the same dimensionality"); Vector vector = new Vector(v.NDimensions); for (int i = 0; i < v.NDimensions; i++) { vector[i] = this[i] - v[i]; } return vector; }
/// <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; }
/// <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); } } }
/// <summary> /// Construct an initial simplex, given starting guesses for the constants, and /// initial step sizes for each dimension /// </summary> /// <param name="simplexConstants"></param> /// <returns></returns> private static Vector[] _initializeVertices(SimplexConstant[] simplexConstants) { int numDimensions = simplexConstants.Length; Vector[] vertices = new Vector[numDimensions + 1]; // define one point of the simplex as the given initial guesses Vector p0 = new Vector(numDimensions); for (int i = 0; i < numDimensions; i++) { p0[i] = simplexConstants[i].Value; } // now fill in the vertices, creating the additional points as: // P(i) = P(0) + Scale(i) * UnitVector(i) vertices[0] = p0; for (int i = 0; i < numDimensions; i++) { double scale = simplexConstants[i].InitialPerturbation; Vector unitVector = new Vector(numDimensions); unitVector[i] = 1; vertices[i + 1] = p0.Add(unitVector.Multiply(scale)); #if DEBUG Console.Write(i+":" + vertices[i + 1].ToString() + "=="); #endif } #if DEBUG Console.WriteLine(""); #endif return vertices; }
/// <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> /// Compute the centroid of all points except the worst /// </summary> /// <param name="vertices"></param> /// <param name="errorProfile"></param> /// <returns></returns> private static Vector _computeCentroid(Vector[] vertices, ErrorProfile errorProfile) { int numVertices = vertices.Length; // find the centroid of all points except the worst one Vector centroid = new Vector(numVertices - 1); for (int i = 0; i < numVertices; i++) { if (i != errorProfile.HighestIndex) { centroid = centroid.Add(vertices[i]); } } return centroid.Multiply(1.0d / (numVertices - 1)); }
/// <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> /// Compute the dot product of this vector and the given vector /// </summary> /// <param name="v"></param> /// <returns></returns> public double DotProduct(Vector v) { if (v.NDimensions != this.NDimensions) throw new ArgumentException("Can only compute dot product for vectors of the same dimensionality"); double sum = 0; for (int i = 0; i < v.NDimensions; i++) { sum += this[i] * v[i]; } return sum; }