public override double findAlphaStar(double[] x, double[] dir) { // include the first two points in this SortedList (essentially, the a, b and c). var alphaAndF = new SortedList <double, double> { { 0.0, calcF(x, 0.0, dir) }, { stepSize, calcF(x, stepSize, dir) } }; // third point is based on if second point is better or worse if (alphaAndF[stepSize] <= alphaAndF[0.0]) { alphaAndF.Add(3 * stepSize, calcF(x, 3 * stepSize, dir)); } else { alphaAndF.Add(stepSize / 2, calcF(x, stepSize / 2, dir)); } var k = 0; var fMin = alphaAndF.Values.Min(); var minIndex = alphaAndF.IndexOfValue(fMin); #region start main loop while (((Math.Abs(alphaAndF.Keys[2] - alphaAndF.Keys[0]) / 2) > epsilon) && (k++ < kMax)) { k++; double alphaNew; DSCPowellLoopStatus loopStatus; #region find new alpha if (!quadraticApprox(out alphaNew, alphaAndF)) { /* if the quadratic approximatoin fails, we make note of it with this enumerator. */ loopStatus = DSCPowellLoopStatus.SecondDerivNegative; SearchIO.output("<<< uh-oh! negative 2nd deriv @ k=" + k + "!>>>", 5); } else if (alphaAndF.Keys.Contains(alphaNew)) { /* if the alpha is already one of the three, then no point in keeping it. */ loopStatus = DSCPowellLoopStatus.NewPointAlreadyFound; SearchIO.output("<<< uh-oh! new point is a repeat @ k=" + k + "!>>>", 5); } else { var fNew = calcF(x, alphaNew, dir); if (fNew > alphaAndF.Values.Min() && NewPointIsFarthest(alphaNew, alphaAndF.Keys, minIndex)) { SearchIO.output("<<< uh-oh! new point is not best and too far away @ k=" + k + "!>>>", 5); /* the new point is not the best and is farthest from the current best, so it will simply * be deleted after it is added. That's not good. */ loopStatus = DSCPowellLoopStatus.NewPointIsFarthest; } else { /* whew! it looks like the new point (point d) is a keeper */ loopStatus = DSCPowellLoopStatus.Normal; alphaAndF.Add(alphaNew, fNew); } } #endregion #region if alpha via quadratic approximation failed, then set here. if (loopStatus != DSCPowellLoopStatus.Normal) { switch (minIndex) { case 0: alphaNew = alphaAndF.Keys[0] + (alphaAndF.Keys[0] - alphaAndF.Keys[2]); break; case 1: alphaNew = (alphaAndF.Keys[0] + alphaAndF.Keys[1] + alphaAndF.Keys[2]) / 3; break; case 2: alphaNew = alphaAndF.Keys[2] + (alphaAndF.Keys[2] - alphaAndF.Keys[0]); break; } alphaAndF.Add(alphaNew, calcF(x, alphaNew, dir)); } #endregion #region remove farthest value from min fMin = alphaAndF.Values.Min(); minIndex = alphaAndF.IndexOfValue(fMin); switch (minIndex) { case 0: alphaAndF.RemoveAt(3); break; case 1: if (alphaAndF.Keys[3] - alphaAndF.Keys[1] > alphaAndF.Keys[1] - alphaAndF.Keys[0]) { alphaAndF.RemoveAt(3); } else { alphaAndF.RemoveAt(0); } break; case 2: if (alphaAndF.Keys[3] - alphaAndF.Keys[2] > alphaAndF.Keys[2] - alphaAndF.Keys[0]) { alphaAndF.RemoveAt(3); } else { alphaAndF.RemoveAt(0); } break; case 3: alphaAndF.RemoveAt(0); break; } #endregion fMin = alphaAndF.Values.Min(); minIndex = alphaAndF.IndexOfValue(fMin); } #endregion return(alphaAndF.Keys[minIndex]); }
/// <summary> /// Runs the specified x star. /// </summary> /// <param name="xStar">The x star.</param> /// <returns>System.Double.</returns> protected override double run(out double[] xStar) { fStar = calc_f(x); // Set initial direction vectors to the basis vectors var directions = new double[n][]; var distanceTraveled = new double[n]; var steps = new double[n]; for (int i = 0; i < n; i++) { var dir = new double[n]; dir[i] = 1.0; directions[i] = dir; } // Now, start the main loop while (notConverged(k++, numEvals, fStar, x)) { SearchIO.output("iter=" + k, 2); // first, we move in each direction using simple line search for (var i = 0; i < n; i++) { steps[i] = initialStepSize; distanceTraveled[i] = 0.0; var oneSuccess = false; var oneFailure = false; while (!(oneFailure && oneSuccess) && Math.Abs(steps[i]) > minimumStepSize) { var xNew = x.add(directions[i].multiply(steps[i])); var fNew = calc_f(xNew); if (fNew < fStar) { oneSuccess = true; x = xNew; fStar = fNew; distanceTraveled[i] += steps[i]; steps[i] *= alpha; } else { oneFailure = true; steps[i] *= beta; } } } // finding new search directions var newDirs = new double[n][]; for (int i = 0; i < n; i++) { newDirs[i] = new double[n]; for (int j = i; j < n; j++) { newDirs[i] = newDirs[i].add(directions[j].multiply(distanceTraveled[j])); } } initialStepSize = newDirs[0].norm2(); if (initialStepSize < minimumStepSize) { stepTooSmallConvergence.hasConverged = true; continue; } directions[0] = newDirs[0].divide(initialStepSize); for (int i = 1; i < n; i++) { var newDir = (double[])newDirs[i].Clone(); for (int j = 0; j < i; j++) { newDir = newDir.subtract(directions[j].multiply(newDirs[i].dotProduct(directions[j]))); } var length = newDir.norm2(); directions[i] = (length == 0) ? new double[n] : newDir.divide(length); } // Next, we update the directions using the Gram-Schmidt Orthogonalization } xStar = x; return(fStar); }