public void T01_OneDimensional() { const double Accuracy = 1.5e-7; // sin(x+1) + x/2 has local minima at -2/3PI-1, 4/3PI-1, 10/3PI-1, etc. DifferentiableFunction function = new DifferentiableFunction(x => Math.Sin(x + 1) + x / 2, x => Math.Cos(x + 1) + 0.5); Func <double, double> ndFunction = function.Evaluate; // create a version without derivative information // the three minima above are located between -5 and 13, so we should be able to find them with BracketInward() List <MinimumBracket> brackets = Minimize.BracketInward(function, -5, 13, 3).ToList(); Assert.AreEqual(3, brackets.Count); // ensure we found them all List <double> minima = new List <double>(); // for each bracket, try to find it using all available methods foreach (MinimumBracket bracket in brackets) { double x = Minimize.GoldenSection(function, bracket); // first use golden section search, which is the most reliable Assert.AreEqual(x, Minimize.Brent(function, bracket), Accuracy); // then make sure Brent's method gives a similar answer, both with Assert.AreEqual(x, Minimize.Brent(ndFunction, bracket), Accuracy); // and without the derivative minima.Add(x); } minima.Sort(); // then sort the results to put them in a known order and make sure they're equal to the expected values Assert.AreEqual(3, minima.Count); Assert.AreEqual(Math.PI * -2 / 3 - 1, minima[0], Accuracy); Assert.AreEqual(Math.PI * 4 / 3 - 1, minima[1], Accuracy); Assert.AreEqual(Math.PI * 10 / 3 - 1, minima[2], Accuracy); // now test BracketOutward MinimumBracket b; Assert.IsFalse(Minimize.BracketOutward(x => x, 0, 1, out b)); // make sure it fails with functions that have no minimum Assert.IsTrue(Minimize.BracketOutward(x => 5, 0, 1, out b)); // but succeeds with constant functions Assert.IsTrue(Minimize.BracketOutward(function, 0, 1, out b)); // and with our sample function // make sure it searches in a downhill direction, as designed Assert.AreEqual(Math.PI * -2 / 3 - 1, Minimize.GoldenSection(function, b), Accuracy); Assert.IsTrue(Minimize.BracketOutward(function, 1, 2, out b)); Assert.AreEqual(Math.PI * 4 / 3 - 1, Minimize.GoldenSection(function, b), Accuracy); // try a function with a singularity, for kicks ndFunction = x => Math.Cos(x) / (x - 1); Assert.AreEqual(1, Minimize.GoldenSection(ndFunction, new MinimumBracket(-1, -0.1, 1)), Accuracy); Assert.AreEqual(1, Minimize.Brent(ndFunction, new MinimumBracket(-1, -0.1, 1)), Accuracy); }
public void T03_Constrained() { // a constrained minimization problem using a barrier function to minimize x^2 subject to x > 5 MinimumBracket bracket = Minimize.BracketInward(new BarrierFunction(1), 5 + (5.0 / 2) * IEEE754.DoublePrecision, 100, 100).First(); double value; Assert.AreEqual(5, Minimize.Brent(new BarrierFunction(1e-10), bracket, out value), 1.2e-7); Assert.AreEqual(25, value, 1.2e-6); // test a constrained minimization problem using various methods ConstrainedMinimizer minimizer; double[] point; foreach (ConstraintEnforcement method in (ConstraintEnforcement[])Enum.GetValues(typeof(ConstraintEnforcement))) { // test the same problem using the ConstrainedMinimizer point = new double[2] { 5, 8 }; minimizer = new ConstrainedMinimizer(new ConstraintTestFunction()) { ConstraintEnforcement = method }; minimizer.SetBounds(0, 1, double.PositiveInfinity); minimizer.SetBounds(1, 3, 9); value = minimizer.Minimize(point); switch (method) { case ConstraintEnforcement.InverseBarrier: // ~ 220 function calls and 180 gradient evaluations Assert.AreEqual(9, value, 1.4e-8); Assert.AreEqual(1, point[0], 2.4e-10); Assert.AreEqual(3, point[1], 4.1e-10); break; case ConstraintEnforcement.LinearPenalty: // ~ 870 function calls and 120 gradient evaluations Assert.AreEqual(9, value, 4.4e-11); Assert.AreEqual(1, point[0], 2.5e-12); Assert.AreEqual(3, point[1], 2.5e-12); break; case ConstraintEnforcement.LogBarrier: // ~ 140 function calls and 130 gradient evaluations Assert.AreEqual(9, value, 5.1e-9); Assert.AreEqual(1, point[0], 6e-12); Assert.AreEqual(3, point[1], 1.7e-11); break; case ConstraintEnforcement.QuadraticPenalty: // ~ 670 function calls and 170 gradient evaluations Assert.AreEqual(9, value, 9e-9); Assert.AreEqual(1, point[0], 9e-10); Assert.AreEqual(3, point[1], 4e-10); break; default: throw new NotImplementedException(); } } // test the constrained minimizer with a tricky problem -- finding the minimum of the rosenbrock banana constrained to an // arbitrary line that doesn't pass through the minimum of the original problem minimizer = new ConstrainedMinimizer(new RosenbrockBanana()); minimizer.AddConstraint(new LineConstraint(-1.5, -1.5, 0, 1.5, 0)); point = new double[2] { -1.2, 2 }; value = minimizer.Minimize(point); Assert.AreEqual(2.4975, value, 2e-9); Assert.AreEqual(-0.57955689989313142185, point[0], 8e-10); Assert.AreEqual(0.34088620021373715629, point[1], 1e-9); }