Skip to content

Commit ed1b7ab

Browse files
authored
Merge pull request #858 from Shiney/master
Fix issue 510
2 parents a50d68d + 3975772 commit ed1b7ab

2 files changed

Lines changed: 46 additions & 5 deletions

File tree

src/Numerics.Tests/OptimizationTests/BfgsMinimizerTests.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
using System.Collections.Generic;
3737
using System.Collections;
3838
using NUnit.Framework.Interfaces;
39+
using MathNet.Numerics.LinearAlgebra;
40+
using MathNet.Numerics.Optimization.ObjectiveFunctions;
3941

4042
namespace MathNet.Numerics.UnitTests.OptimizationTests
4143
{
@@ -155,5 +157,44 @@ public void Mgh_Tests(TestFunctions.TestCase test_case)
155157
var success = (abs_min <= 1 && abs_err < 1e-3) || (abs_min > 1 && rel_err < 1e-3);
156158
Assert.That(success, "Minimal function value is not as expected.");
157159
}
160+
161+
162+
[Test]
163+
public void BfgsMinimizer_MinimizesProperlyWhenConstrainedInOneVariable()
164+
{
165+
// Test comes from github issue 510
166+
// https://github.com/mathnet/mathnet-numerics/issues/510
167+
Func<Vector<double>, double> function = (Vector<double> vectorArg) =>
168+
{
169+
double x = vectorArg[0];
170+
double y = -1.0 * Math.Exp(-x * x);
171+
return y;
172+
};
173+
174+
double gradientTolerance = 1e-10;
175+
double parameterTolerance = 1e-10;
176+
double functionProgressTolerance = 1e-10;
177+
int maxIterations = 1000;
178+
179+
var initialGuess = new DenseVector(new[] { -1.0 });
180+
181+
// Bad Bound
182+
var lowerBound = new DenseVector(new[] { -2.0 });
183+
var upperBound = new DenseVector(new[] { 2.0 });
184+
185+
186+
var objective = ObjectiveFunction.Value(function);
187+
var objectiveWithGradient = new ForwardDifferenceGradientObjectiveFunction(objective, lowerBound, upperBound);
188+
var algorithm = new BfgsBMinimizer(gradientTolerance, parameterTolerance, functionProgressTolerance, maxIterations);
189+
var result = algorithm.FindMinimum(objectiveWithGradient, lowerBound, upperBound, initialGuess);
190+
191+
var resultVector = result.MinimizingPoint;
192+
double xResult = resultVector[0];
193+
194+
// (actual minimum at zero)
195+
var abs_err = Math.Abs(xResult);
196+
var success = abs_err < 1e-6;
197+
Assert.That(success, "Minimal function value is not as expected.");
198+
}
158199
}
159200
}

src/Numerics/Optimization/QuadraticGradientProjectionSearch.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ public static GradientProjectionResult Search(Vector<double> x0, Vector<double>
8080
// while minimum of the last quadratic piece observed is beyond the interval searched
8181
while (true)
8282
{
83+
if (jj + 1 >= orderedBreakpoint.Count - 1)
84+
{
85+
isFixed[isFixed.Count - 1] = true;
86+
return new GradientProjectionResult(x + maxS * d, lowerBound.Count, isFixed);
87+
}
8388
// update data to the beginning of the interval we're searching
8489
jj += 1;
8590
x = x + d * maxS;
@@ -104,11 +109,6 @@ public static GradientProjectionResult Search(Vector<double> x0, Vector<double>
104109

105110
if (sMin < maxS)
106111
return new GradientProjectionResult(x + sMin * d, fixedCount, isFixed);
107-
else if (jj + 1 >= orderedBreakpoint.Count - 1)
108-
{
109-
isFixed[isFixed.Count - 1] = true;
110-
return new GradientProjectionResult(x + maxS * d, lowerBound.Count, isFixed);
111-
}
112112
}
113113
}
114114

0 commit comments

Comments
 (0)