forked from tsai/mathnet-numerics
Browse Source
* Changed file and class names from TestClassName to ClassNameTests to better conform with other parts of Math.Net * Added some organizational abstractions to simplify adding test cases. * Added test cases based on several functions from Testing Unconstrained Optimization Software Jorge J. Moré, Burton S. Garbow, Kenneth E. Hillstrom ACM Transactions on Mathematical Software, Vol 7, No. 1, March 1981, Pages 17-41. * At this point, most test functions are low-dimensional, well-scaled, unimodal functions. * There are test failures for Conjugate Gradient and Newton unconstrained minimizers. Currently I believe these to be failures of the algorithm, rather than failures of implementation, but it hasn't been investigated thoroughly.unified_optimization
23 changed files with 2217 additions and 44 deletions
@ -0,0 +1,85 @@ |
|||
using System; |
|||
using MathNet.Numerics.LinearAlgebra.Double; |
|||
using MathNet.Numerics.Optimization; |
|||
using NUnit.Framework; |
|||
using MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests |
|||
{ |
|||
[TestFixture] |
|||
public class ConjugateGradientMinimizerTests |
|||
{ |
|||
[Test] |
|||
public void FindMinimum_Rosenbrock_Easy() |
|||
{ |
|||
var obj = ObjectiveFunction.Gradient(RosenbrockFunction.Value, RosenbrockFunction.Gradient); |
|||
var solver = new ConjugateGradientMinimizer(1e-5, 1000); |
|||
var result = solver.FindMinimum(obj, new DenseVector(new[]{1.2,1.2})); |
|||
|
|||
Assert.That(Math.Abs(result.MinimizingPoint[0]-1.0), Is.LessThan(1e-3)); |
|||
Assert.That(Math.Abs(result.MinimizingPoint[1] - 1.0), Is.LessThan(1e-3)); |
|||
} |
|||
|
|||
[Test] |
|||
public void FindMinimum_Rosenbrock_Hard() |
|||
{ |
|||
var obj = ObjectiveFunction.Gradient(RosenbrockFunction.Value, RosenbrockFunction.Gradient); |
|||
var solver = new ConjugateGradientMinimizer(1e-5, 1000); |
|||
var result = solver.FindMinimum(obj, new DenseVector(new[] { -1.2, 1.0 })); |
|||
|
|||
Assert.That(Math.Abs(result.MinimizingPoint[0] - 1.0), Is.LessThan(1e-3)); |
|||
Assert.That(Math.Abs(result.MinimizingPoint[1] - 1.0), Is.LessThan(1e-3)); |
|||
} |
|||
|
|||
private class MghTestCaseEnumerator : IEnumerable<ITestCaseData> |
|||
{ |
|||
public IEnumerator<ITestCaseData> GetEnumerator() |
|||
{ |
|||
return |
|||
RosenbrockFunction2.TestCases |
|||
.Concat(BealeFunction.TestCases) |
|||
.Concat(HelicalValleyFunction.TestCases) |
|||
.Concat(MeyerFunction.TestCases) |
|||
.Concat(PowellSingularFunction.TestCases) |
|||
.Concat(WoodFunction.TestCases) |
|||
.Concat(BrownAndDennisFunction.TestCases) |
|||
.Where(x => x.IsUnbounded) |
|||
.Select(x => new TestCaseData(x) |
|||
.SetName(x.FullName) |
|||
) |
|||
.GetEnumerator(); |
|||
} |
|||
|
|||
IEnumerator IEnumerable.GetEnumerator() |
|||
{ |
|||
return this.GetEnumerator(); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[TestCaseSource(typeof(MghTestCaseEnumerator))] |
|||
public void Mgh_Tests(TestFunctions.TestCase test_case) |
|||
{ |
|||
var obj = new MghObjectiveFunction(test_case.Function, true, true); |
|||
var solver = new ConjugateGradientMinimizer(1e-8, 1000); |
|||
|
|||
var result = solver.FindMinimum(obj, test_case.InitialGuess); |
|||
|
|||
if (test_case.MinimizingPoint != null) |
|||
{ |
|||
Assert.That((result.MinimizingPoint - test_case.MinimizingPoint).L2Norm(), Is.LessThan(1e-3)); |
|||
} |
|||
|
|||
var val1 = result.FunctionInfoAtMinimum.Value; |
|||
var val2 = test_case.MinimalValue; |
|||
var abs_min = Math.Min(Math.Abs(val1), Math.Abs(val2)); |
|||
var abs_err = Math.Abs(val1 - val2); |
|||
var rel_err = abs_err / abs_min; |
|||
var success = (abs_min <= 1 && abs_err < 1e-3) || (abs_min > 1 && rel_err < 1e-3); |
|||
Assert.That(success, "Minimal function value is not as expected."); |
|||
} |
|||
} |
|||
} |
|||
@ -1,33 +0,0 @@ |
|||
using System; |
|||
using MathNet.Numerics.LinearAlgebra.Double; |
|||
using MathNet.Numerics.Optimization; |
|||
using NUnit.Framework; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests |
|||
{ |
|||
[TestFixture] |
|||
public class TestConjugateGradientMinimizer |
|||
{ |
|||
[Test] |
|||
public void FindMinimum_Rosenbrock_Easy() |
|||
{ |
|||
var obj = ObjectiveFunction.Gradient(RosenbrockFunction.Value, RosenbrockFunction.Gradient); |
|||
var solver = new ConjugateGradientMinimizer(1e-5, 1000); |
|||
var result = solver.FindMinimum(obj, new DenseVector(new[]{1.2,1.2})); |
|||
|
|||
Assert.That(Math.Abs(result.MinimizingPoint[0]-1.0), Is.LessThan(1e-3)); |
|||
Assert.That(Math.Abs(result.MinimizingPoint[1] - 1.0), Is.LessThan(1e-3)); |
|||
} |
|||
|
|||
[Test] |
|||
public void FindMinimum_Rosenbrock_Hard() |
|||
{ |
|||
var obj = ObjectiveFunction.Gradient(RosenbrockFunction.Value, RosenbrockFunction.Gradient); |
|||
var solver = new ConjugateGradientMinimizer(1e-5, 1000); |
|||
var result = solver.FindMinimum(obj, new DenseVector(new[] { -1.2, 1.0 })); |
|||
|
|||
Assert.That(Math.Abs(result.MinimizingPoint[0] - 1.0), Is.LessThan(1e-3)); |
|||
Assert.That(Math.Abs(result.MinimizingPoint[1] - 1.0), Is.LessThan(1e-3)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
using MathNet.Numerics.Optimization; |
|||
using MathNet.Numerics.Optimization.ObjectiveFunctions; |
|||
using MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions; |
|||
using MathNet.Numerics.LinearAlgebra.Double; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests |
|||
{ |
|||
public class MghObjectiveFunction : LazyObjectiveFunctionBase |
|||
{ |
|||
private ITestFunction TestFunction; |
|||
|
|||
public MghObjectiveFunction(ITestFunction testFunction, bool use_gradient, bool use_hessian) |
|||
: base(use_gradient, use_hessian) |
|||
{ |
|||
this.TestFunction = testFunction; |
|||
} |
|||
|
|||
public override IObjectiveFunction CreateNew() |
|||
{ |
|||
return new MghObjectiveFunction(this.TestFunction, this.IsGradientSupported, this.IsHessianSupported); |
|||
} |
|||
|
|||
protected override void EvaluateValue() |
|||
{ |
|||
this.Value = this.TestFunction.SsqValue(this.Point); |
|||
} |
|||
|
|||
protected override void EvaluateGradient() |
|||
{ |
|||
if (this.IsGradientSupported) |
|||
{ |
|||
if (this._gradientValue == null) |
|||
this.Gradient = new DenseVector(this.TestFunction.ParameterDimension); |
|||
this.TestFunction.SsqGradientByRef(this.Point, _gradientValue); |
|||
} |
|||
} |
|||
|
|||
protected override void EvaluateHessian() |
|||
{ |
|||
if (this.IsHessianSupported) |
|||
{ |
|||
if (this._hessianValue == null) |
|||
this.Hessian = new DenseMatrix(this.TestFunction.ParameterDimension, this.TestFunction.ParameterDimension); |
|||
this.TestFunction.SsqHessianByRef(this.Point, _hessianValue); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,309 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions; |
|||
using NUnit.Framework; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
using System.Collections; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests |
|||
{ |
|||
[TestFixture] |
|||
public class TestFunctionTests |
|||
{ |
|||
private static IEnumerable<TestFunctions.TestCase> MghCases |
|||
{ |
|||
get |
|||
{ |
|||
return Enumerable.Empty<TestFunctions.TestCase>() |
|||
.Concat(RosenbrockFunction2.TestCases) |
|||
.Concat(BealeFunction.TestCases) |
|||
.Concat(HelicalValleyFunction.TestCases) |
|||
.Concat(MeyerFunction.TestCases) |
|||
.Concat(PowellSingularFunction.TestCases) |
|||
.Concat(WoodFunction.TestCases) |
|||
.Concat(BrownAndDennisFunction.TestCases); |
|||
} |
|||
} |
|||
|
|||
private class MghCaseEnumerator : IEnumerable<TestCaseData> |
|||
{ |
|||
public string CategoryName { get; protected set; } |
|||
|
|||
public MghCaseEnumerator(string category_name) |
|||
{ |
|||
this.CategoryName = category_name; |
|||
} |
|||
|
|||
public virtual IEnumerator<TestCaseData> GetEnumerator() |
|||
{ |
|||
return MghCases |
|||
.Select(x => |
|||
new TestCaseData(x) |
|||
.SetName($"{x.FullName} {this.CategoryName}") |
|||
).GetEnumerator(); |
|||
} |
|||
|
|||
IEnumerator IEnumerable.GetEnumerator() |
|||
{ |
|||
return this.GetEnumerator(); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void Smoke_Construction() |
|||
{ |
|||
var c = new TestCase() |
|||
{ |
|||
InitialGuess = new double[] { 1, 2, 3 }, |
|||
MinimizingPoint = new double[] { 1, 1, 1 }, |
|||
MinimalValue = 0 |
|||
}; |
|||
} |
|||
|
|||
private class ValueAtMinimumSource : MghCaseEnumerator |
|||
{ |
|||
public ValueAtMinimumSource() : base("ValueAtMinimum") { } |
|||
|
|||
public override IEnumerator<TestCaseData> GetEnumerator() |
|||
{ |
|||
return MghCases |
|||
.Where(x => x.MinimizingPoint != null) |
|||
.Select(x => |
|||
new TestCaseData(x) |
|||
.SetName($"{x.FullName} {this.CategoryName}") |
|||
) |
|||
.GetEnumerator(); |
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
[TestCaseSource(typeof(ValueAtMinimumSource))] |
|||
public void ValueAtMinimum(TestFunctions.TestCase test_case) |
|||
{ |
|||
if (test_case.MinimizingPoint != null) |
|||
{ |
|||
var value_at_minimum = test_case.Function.SsqValue(test_case.MinimizingPoint); |
|||
Assert.That( |
|||
Math.Abs(value_at_minimum - test_case.MinimalValue) < 1e-3, |
|||
$"Function value at minimum not as expected." |
|||
); |
|||
} |
|||
} |
|||
|
|||
private class GradientAtStartSource : MghCaseEnumerator |
|||
{ |
|||
public GradientAtStartSource() : base("GradientAtStart") { } |
|||
} |
|||
|
|||
[Test] |
|||
[TestCaseSource(typeof(GradientAtStartSource))] |
|||
public void GradientAtStart(TestFunctions.TestCase test_case) |
|||
{ |
|||
var a_grad = test_case.Function.SsqGradient(test_case.InitialGuess); |
|||
var fd_grad = Vector<double>.Build.Dense(test_case.Function.ParameterDimension, 0.0); |
|||
|
|||
for (int ii = 0; ii < test_case.Function.ParameterDimension; ++ii) |
|||
{ |
|||
var h = 1e-6; |
|||
|
|||
var bump_up = test_case.InitialGuess.Clone(); |
|||
bump_up[ii] += h; |
|||
var bump_down = test_case.InitialGuess.Clone(); |
|||
bump_down[ii] -= h; |
|||
|
|||
var up_val = test_case.Function.SsqValue(bump_up); |
|||
var down_val = test_case.Function.SsqValue(bump_down); |
|||
|
|||
fd_grad[ii] = 0.5 * (up_val - down_val) / h; |
|||
} |
|||
|
|||
for (int ii = 0; ii < test_case.Function.ParameterDimension; ++ii) |
|||
{ |
|||
var val1 = a_grad[ii]; |
|||
var val2 = fd_grad[ii]; |
|||
var min_abs_val = Math.Min(Math.Abs(val1), Math.Abs(val2)); |
|||
if (min_abs_val <= 1) |
|||
Assert.That(Math.Abs(val1 - val2) < 1e-3, $"Problem with gradient value at start point."); |
|||
else |
|||
Assert.That(Math.Abs(val1 - val2) / min_abs_val < 1e-3, $"Problem with gradient value at start point."); |
|||
} |
|||
} |
|||
|
|||
private class HessianAtStartSource : MghCaseEnumerator |
|||
{ |
|||
public HessianAtStartSource() : base("HessianAtStart") { } |
|||
|
|||
public override IEnumerator<TestCaseData> GetEnumerator() |
|||
{ |
|||
return MghCases |
|||
.Where(x => x.MinimizingPoint != null) |
|||
.Select(x => |
|||
new TestCaseData(x) |
|||
.SetName($"{x.FullName} {this.CategoryName}") |
|||
) |
|||
.GetEnumerator(); |
|||
} |
|||
} |
|||
[Test] |
|||
[TestCaseSource(typeof(HessianAtStartSource))] |
|||
public void HessianAtStart(TestFunctions.TestCase test_case) |
|||
{ |
|||
var a_hess = test_case.Function.SsqHessian(test_case.InitialGuess); |
|||
var fd_hess = Matrix<double>.Build.Dense(test_case.Function.ParameterDimension, test_case.Function.ParameterDimension); |
|||
for (int ii = 0; ii < test_case.Function.ParameterDimension; ++ii) |
|||
{ |
|||
for (int jj = 0; jj < test_case.Function.ParameterDimension; ++jj) |
|||
{ |
|||
var h1 = 1e-3 * Math.Max(1.0, Math.Abs(test_case.InitialGuess[ii])); |
|||
var h2 = 1e-3 * Math.Max(1.0, Math.Abs(test_case.InitialGuess[jj])); |
|||
|
|||
var bump_uu = test_case.InitialGuess.Clone(); |
|||
bump_uu[ii] += h1; |
|||
bump_uu[jj] += h2; |
|||
|
|||
var bump_dd = test_case.InitialGuess.Clone(); |
|||
bump_dd[ii] -= h1; |
|||
bump_dd[jj] -= h2; |
|||
|
|||
var bump_ud = test_case.InitialGuess.Clone(); |
|||
bump_ud[ii] += h1; |
|||
bump_ud[jj] -= h2; |
|||
|
|||
var bump_du = test_case.InitialGuess.Clone(); |
|||
bump_du[ii] -= h1; |
|||
bump_du[jj] += h2; |
|||
|
|||
var val_uu = test_case.Function.SsqValue(bump_uu); |
|||
var val_dd = test_case.Function.SsqValue(bump_dd); |
|||
var val_ud = test_case.Function.SsqValue(bump_ud); |
|||
var val_du = test_case.Function.SsqValue(bump_du); |
|||
|
|||
fd_hess[ii, jj] = (val_uu - val_ud + val_dd - val_du) / (4 * h1 * h2); |
|||
} |
|||
} |
|||
|
|||
for (int ii = 0; ii < test_case.Function.ParameterDimension; ++ii) |
|||
{ |
|||
for (int jj = 0; jj < test_case.Function.ParameterDimension; ++jj) |
|||
{ |
|||
var val1 = fd_hess[ii, jj]; |
|||
var val2 = a_hess[ii, jj]; |
|||
|
|||
var abs_min = Math.Min(Math.Abs(val1), Math.Abs(val2)); |
|||
if (abs_min <= 1) |
|||
{ |
|||
Assert.That(Math.Abs(val1 - val2) < 1e-3, $"Problem with hessian at start point."); |
|||
} |
|||
else |
|||
{ |
|||
Assert.That(Math.Abs(val1 - val2) / abs_min < 0.05, $"Problem with hessian at start point."); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
private class ItemGradientAtStartSource : MghCaseEnumerator |
|||
{ |
|||
public ItemGradientAtStartSource() : base("ItemGradientAtStart") { } |
|||
} |
|||
|
|||
[Test] |
|||
[TestCaseSource(typeof(ItemGradientAtStartSource))] |
|||
public void ItemGradientAtStart(TestFunctions.TestCase test_case) |
|||
{ |
|||
for (var item_index = 0; item_index < test_case.Function.ItemDimension; ++item_index) |
|||
{ |
|||
|
|||
var a_grad = test_case.Function.ItemGradient(test_case.InitialGuess, item_index); |
|||
var h = 1e-4; |
|||
var fd_grad = Vector<double>.Build.Dense(test_case.Function.ParameterDimension, 0.0); |
|||
|
|||
for (int ii = 0; ii < test_case.Function.ParameterDimension; ++ii) |
|||
{ |
|||
var bump_up = test_case.InitialGuess.Clone(); |
|||
bump_up[ii] += h; |
|||
var bump_down = test_case.InitialGuess.Clone(); |
|||
bump_down[ii] -= h; |
|||
|
|||
var up_val = test_case.Function.ItemValue(bump_up, item_index); |
|||
var down_val = test_case.Function.ItemValue(bump_down, item_index); |
|||
|
|||
fd_grad[ii] = 0.5 * (up_val - down_val) / h; |
|||
} |
|||
|
|||
for (int ii = 0; ii < test_case.Function.ParameterDimension; ++ii) |
|||
{ |
|||
Assert.That(Math.Abs(fd_grad[ii] - a_grad[ii]) < 1e-3, $"Failed for parameter {ii}"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private class ItemHessianAtStartSource : MghCaseEnumerator |
|||
{ |
|||
public ItemHessianAtStartSource() : base("ItemHessianAtStart") { } |
|||
} |
|||
|
|||
[Test] |
|||
[TestCaseSource(typeof(ItemHessianAtStartSource))] |
|||
public void ItemHessianAtStart(TestFunctions.TestCase test_case) |
|||
{ |
|||
for (var item_index = 0; item_index < test_case.Function.ItemDimension; ++item_index) |
|||
{ |
|||
var a_hess = test_case.Function.ItemHessian(test_case.InitialGuess, item_index); |
|||
var h = 1e-4; |
|||
var fd_hess = Matrix<double>.Build.Dense(test_case.Function.ParameterDimension, test_case.Function.ParameterDimension); |
|||
for (int ii = 0; ii < test_case.Function.ParameterDimension; ++ii) |
|||
{ |
|||
for (int jj = 0; jj < test_case.Function.ParameterDimension; ++jj) |
|||
{ |
|||
var bump_uu = test_case.InitialGuess.Clone(); |
|||
bump_uu[ii] += h; |
|||
bump_uu[jj] += h; |
|||
|
|||
var bump_dd = test_case.InitialGuess.Clone(); |
|||
bump_dd[ii] -= h; |
|||
bump_dd[jj] -= h; |
|||
|
|||
var bump_ud = test_case.InitialGuess.Clone(); |
|||
bump_ud[ii] += h; |
|||
bump_ud[jj] -= h; |
|||
|
|||
var bump_du = test_case.InitialGuess.Clone(); |
|||
bump_du[ii] -= h; |
|||
bump_du[jj] += h; |
|||
|
|||
var val_uu = test_case.Function.ItemValue(bump_uu, item_index); |
|||
var val_dd = test_case.Function.ItemValue(bump_dd, item_index); |
|||
var val_ud = test_case.Function.ItemValue(bump_ud, item_index); |
|||
var val_du = test_case.Function.ItemValue(bump_du, item_index); |
|||
|
|||
fd_hess[ii, jj] = (val_uu - val_ud + val_dd - val_du) / (4 * h * h); |
|||
} |
|||
} |
|||
|
|||
for (int ii = 0; ii < test_case.Function.ParameterDimension; ++ii) |
|||
{ |
|||
for (int jj = 0; jj < test_case.Function.ParameterDimension; ++jj) |
|||
{ |
|||
var val1 = fd_hess[ii, jj]; |
|||
var val2 = a_hess[ii, jj]; |
|||
|
|||
var abs_min = Math.Min(Math.Abs(val1), Math.Abs(val2)); |
|||
if (abs_min <= 1) |
|||
{ |
|||
Assert.That(Math.Abs(val1 - val2) < 1e-3, $"Problem with hessian at start point."); |
|||
} |
|||
else |
|||
{ |
|||
Assert.That(Math.Abs(val1 - val2) / abs_min < 0.05, $"Problem with hessian at start point."); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,125 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions |
|||
{ |
|||
public abstract class BaseTestFunction : ITestFunction |
|||
{ |
|||
public abstract string Description { get; } |
|||
public abstract int ParameterDimension { get; } |
|||
public abstract int ItemDimension { get; } |
|||
|
|||
public abstract double ItemValue(Vector<double> x, int itemIndex); |
|||
public abstract void ItemGradientByRef(Vector<double> x, int itemIndex, Vector<double> output); |
|||
public abstract void ItemHessianByRef(Vector<double> x, int itemIndex, Matrix<double> output); |
|||
|
|||
public virtual Vector<double> ItemGradient(Vector<double> x, int itemIndex) |
|||
{ |
|||
var output = new LinearAlgebra.Double.DenseVector(this.ParameterDimension); |
|||
this.ItemGradientByRef(x, itemIndex, output); |
|||
return output; |
|||
} |
|||
|
|||
public virtual Matrix<double> ItemHessian(Vector<double> x, int itemIndex) |
|||
{ |
|||
var output = new LinearAlgebra.Double.DenseMatrix(this.ParameterDimension, this.ParameterDimension); |
|||
this.ItemHessianByRef(x, itemIndex, output); |
|||
return output; |
|||
} |
|||
|
|||
|
|||
public virtual void JacobianbyRef(Vector<double> x, Matrix<double> output) |
|||
{ |
|||
for (int ii = 0; ii < this.ItemDimension; ++ii) |
|||
{ |
|||
var grad = this.ItemGradient(x, ii); |
|||
output.SetRow(ii, grad); |
|||
} |
|||
} |
|||
|
|||
public virtual Matrix<double> Jacobian(Vector<double> x) |
|||
{ |
|||
var output = new LinearAlgebra.Double.DenseMatrix(this.ItemDimension, this.ParameterDimension); |
|||
this.JacobianbyRef(x, output); |
|||
return output; |
|||
} |
|||
|
|||
public virtual void SsqGradientByRef(Vector<double> x, Vector<double> output) |
|||
{ |
|||
if (output.Count != this.ParameterDimension) |
|||
throw new ArgumentException($"Output vector must match parameter dimension of function; expected {this.ParameterDimension}, got {output.Count}."); |
|||
|
|||
for (int jj = 0; jj < this.ParameterDimension; ++jj) |
|||
output[jj] = 0.0; |
|||
var tmp_grad = new LinearAlgebra.Double.DenseVector(this.ParameterDimension); |
|||
double tmp_value = 0.0; |
|||
|
|||
for (int ii = 0; ii < this.ItemDimension; ++ii) |
|||
{ |
|||
tmp_value = this.ItemValue(x, ii); |
|||
this.ItemGradientByRef(x, ii, tmp_grad); |
|||
for (int jj = 0; jj < this.ParameterDimension; ++jj) |
|||
output[jj] += 2 * tmp_value * tmp_grad[jj]; |
|||
} |
|||
} |
|||
|
|||
public virtual Vector<double> SsqGradient(Vector<double> x) |
|||
{ |
|||
var output = new LinearAlgebra.Double.DenseVector(this.ParameterDimension); |
|||
this.SsqGradientByRef(x, output); |
|||
return output; |
|||
} |
|||
|
|||
public virtual void SsqHessianByRef(Vector<double> x, Matrix<double> output) |
|||
{ |
|||
if (output.RowCount != this.ParameterDimension || output.ColumnCount != this.ParameterDimension) |
|||
throw new ArgumentException($"Output matrix must match parameter dimension of function; expected {this.ParameterDimension}x{this.ParameterDimension}, got {output.RowCount}x{output.ColumnCount}."); |
|||
|
|||
for (int ii = 0; ii < this.ParameterDimension; ++ii) |
|||
for (int jj = 0; jj < this.ParameterDimension; ++jj) |
|||
output[ii,jj] = 0.0; |
|||
|
|||
var tmp_grad = new LinearAlgebra.Double.DenseVector(this.ParameterDimension); |
|||
var tmp_hess = new LinearAlgebra.Double.DenseMatrix(this.ParameterDimension, this.ParameterDimension); |
|||
double tmp_value = 0.0; |
|||
|
|||
for (int ii = 0; ii < this.ItemDimension; ++ii) |
|||
{ |
|||
tmp_value = this.ItemValue(x, ii); |
|||
this.ItemGradientByRef(x, ii, tmp_grad); |
|||
this.ItemHessianByRef(x, ii, tmp_hess); |
|||
for (int jj = 0; jj < this.ParameterDimension; ++jj) |
|||
{ |
|||
for (int kk = 0; kk < this.ParameterDimension; ++kk) |
|||
{ |
|||
var increment = 2 * (tmp_value * tmp_hess[jj, kk] + tmp_grad[jj] * tmp_grad[kk]); |
|||
output[jj, kk] += increment; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public virtual Matrix<double> SsqHessian(Vector<double> x) |
|||
{ |
|||
var output = new LinearAlgebra.Double.DenseMatrix(this.ParameterDimension, this.ParameterDimension); |
|||
this.SsqHessianByRef(x, output); |
|||
return output; |
|||
} |
|||
|
|||
public virtual double SsqValue(Vector<double> x) |
|||
{ |
|||
double ssq = 0.0; |
|||
for (int ii = 0; ii < this.ItemDimension; ++ii) |
|||
{ |
|||
var tmp = this.ItemValue(x, ii); |
|||
ssq += tmp * tmp; |
|||
} |
|||
return ssq; |
|||
} |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,97 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions |
|||
{ |
|||
public class BealeFunction : BaseTestFunction |
|||
{ |
|||
public static IEnumerable<TestCase> TestCases |
|||
{ |
|||
get |
|||
{ |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new BealeFunction(), |
|||
InitialGuess = new double[] { 1, 1 }, |
|||
MinimalValue = 0, |
|||
MinimizingPoint = new double[] { 3, 0.5 }, |
|||
CaseName = "unbounded" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new BealeFunction(), |
|||
InitialGuess = new double[] { 1, 1 }, |
|||
MinimalValue = 0, |
|||
MinimizingPoint = new double[] { 3, 0.5 }, |
|||
LowerBound = new double[] { -1000, -1000}, |
|||
UpperBound = new double[] { 1000, 1000}, |
|||
CaseName = "loose bounds" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new BealeFunction(), |
|||
InitialGuess = new double[] { 1, 1 }, |
|||
MinimalValue = 0, |
|||
MinimizingPoint = new double[] { 3, 0.5 }, |
|||
LowerBound = new double[] { 0.6, 0.5 }, |
|||
UpperBound = new double[] { 10, 100 }, |
|||
CaseName = "tight bounds" |
|||
}; |
|||
} |
|||
} |
|||
|
|||
public BealeFunction() { } |
|||
|
|||
public override string Description |
|||
{ |
|||
get |
|||
{ |
|||
return "Beale fun (MGH #5)"; |
|||
} |
|||
} |
|||
|
|||
public override int ItemDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 3; |
|||
} |
|||
} |
|||
|
|||
public override int ParameterDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 2; |
|||
} |
|||
} |
|||
|
|||
public override void ItemGradientByRef(Vector<double> x, int itemIndex, Vector<double> output) |
|||
{ |
|||
int ii = itemIndex + 1; |
|||
output[0] = -1 + Math.Pow(x[1], ii); |
|||
output[1] = ii * x[0] * Math.Pow(x[1], ii - 1); |
|||
} |
|||
|
|||
public override void ItemHessianByRef(Vector<double> x, int itemIndex, Matrix<double> output) |
|||
{ |
|||
int ii = itemIndex + 1; |
|||
output[0, 0] = 0; |
|||
output[0, 1] = ii * Math.Pow(x[1], ii - 1); |
|||
output[1, 0] = ii * Math.Pow(x[1], ii - 1); |
|||
output[1, 1] = (ii - 1) * ii * x[0] * Math.Pow(x[1], ii - 2); |
|||
} |
|||
|
|||
private static readonly double[] y = { 1.5, 2.25, 2.625}; |
|||
|
|||
public override double ItemValue(Vector<double> x, int itemIndex) |
|||
{ |
|||
int ii = itemIndex + 1; |
|||
return y[itemIndex] - x[0] * (1 - Math.Pow(x[1], ii)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,114 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions |
|||
{ |
|||
public class BrownAndDennisFunction : BaseTestFunction |
|||
{ |
|||
public static IEnumerable<TestCase> TestCases |
|||
{ |
|||
get |
|||
{ |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new BrownAndDennisFunction(20), |
|||
InitialGuess = new double[] { 25, 5, -5, -1 }, |
|||
MinimalValue = 85822.2, |
|||
MinimizingPoint = null, |
|||
CaseName = "unbounded" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new BrownAndDennisFunction(20), |
|||
InitialGuess = new double[] { 25, 5, -5, -1 }, |
|||
MinimalValue = 85822.2, |
|||
MinimizingPoint = null, |
|||
LowerBound = new double[] { -1000, -1000, -1000, -1000 }, |
|||
UpperBound = new double[] {1000, 1000, 1000, 1000 }, |
|||
CaseName = "loose bounds" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new BrownAndDennisFunction(20), |
|||
InitialGuess = new double[] { 25, 5, -5, -1 }, |
|||
MinimalValue = 0.88860479e5, |
|||
MinimizingPoint = null, |
|||
LowerBound = new double[] { -10, 0, -100, -20 }, |
|||
UpperBound = new double[] { 100, 15, 0, 0.2 }, |
|||
CaseName = "tight bounds" |
|||
}; |
|||
} |
|||
} |
|||
|
|||
private readonly int _items; |
|||
|
|||
public BrownAndDennisFunction(int items) |
|||
{ |
|||
if (items < 4) |
|||
throw new ArgumentException("items must be >= 4"); |
|||
_items = items; |
|||
} |
|||
|
|||
public override string Description |
|||
{ |
|||
get |
|||
{ |
|||
return "Brown & Dennis fun (MGH #16)"; |
|||
} |
|||
} |
|||
|
|||
public override int ItemDimension |
|||
{ |
|||
get |
|||
{ |
|||
return _items; |
|||
} |
|||
} |
|||
|
|||
public override int ParameterDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 4; |
|||
} |
|||
} |
|||
|
|||
public override void ItemGradientByRef(Vector<double> x, int itemIndex, Vector<double> output) |
|||
{ |
|||
var ii = itemIndex + 1; |
|||
var t = ii / 5.0; |
|||
output[0] = 2 * (x[0] + t * x[1] - Math.Exp(t)); |
|||
output[1] = (2*ii/25.0) * (5 * x[0] + ii * x[1] - 5 * Math.Exp(t)); |
|||
output[2] = 2 * (x[2] + x[3] * Math.Sin(t) - Math.Cos(t)); |
|||
output[3] = 2 * Math.Sin(t) * (x[2] + Math.Sin(t) * x[3] - Math.Cos(t)); |
|||
} |
|||
|
|||
public override void ItemHessianByRef(Vector<double> x, int itemIndex, Matrix<double> output) |
|||
{ |
|||
for (int ii = 0; ii < 4; ++ii) |
|||
for (int jj = 0; jj < 4; ++jj) |
|||
output[ii, jj] = 0; |
|||
var i = itemIndex + 1; |
|||
var t = i / 5.0; |
|||
output[0, 0] = 2; |
|||
output[0, 1] = 2 * t; |
|||
output[1, 0] = 2 * t; |
|||
output[1, 1] = 2 * t * t; |
|||
output[2, 2] = 2; |
|||
output[2, 3] = 2 * Math.Sin(t); |
|||
output[3, 2] = 2 * Math.Sin(t); |
|||
output[3, 3] = 2 * Math.Pow(Math.Sin(t), 2); |
|||
} |
|||
|
|||
public override double ItemValue(Vector<double> x, int itemIndex) |
|||
{ |
|||
var ii = itemIndex + 1; |
|||
var t = ii / 5.0; |
|||
return Math.Pow(x[0] + t * x[1] - Math.Exp(t), 2.0) + Math.Pow(x[2] + x[3] * Math.Sin(t) - Math.Cos(t), 2); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,131 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions |
|||
{ |
|||
public class BrownBadlyScaledFunction : BaseTestFunction |
|||
{ |
|||
public static IEnumerable<TestCase> TestCases |
|||
{ |
|||
get |
|||
{ |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new BrownBadlyScaledFunction(), |
|||
InitialGuess = new double[] { 1, 1 }, |
|||
MinimalValue = 0, |
|||
MinimizingPoint = new double[] { 1e6, 2e-6 }, |
|||
CaseName = "unbounded" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new BrownBadlyScaledFunction(), |
|||
InitialGuess = new double[] { 1, 1 }, |
|||
MinimalValue = 0, |
|||
MinimizingPoint = new double[] { 1e6, 2e-6 }, |
|||
LowerBound = new double[] { -1e8, -1e8 }, |
|||
UpperBound = new double[] { 1e8, 1e8 }, |
|||
CaseName = "loose bounds" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new BrownBadlyScaledFunction(), |
|||
InitialGuess = new double[] { 1, 1 }, |
|||
MinimalValue = 0.784e3, |
|||
MinimizingPoint = new double[] { 1e6, 2e-6 }, |
|||
LowerBound = new double[] { 0, 3e-5 }, |
|||
UpperBound = new double[] { 1e6, 100 }, |
|||
CaseName = "tight bounds" |
|||
}; |
|||
} |
|||
} |
|||
|
|||
public BrownBadlyScaledFunction() { } |
|||
|
|||
public override string Description |
|||
{ |
|||
get |
|||
{ |
|||
return "Brown badly scaled fun (MGH #4)"; |
|||
} |
|||
} |
|||
|
|||
public override int ItemDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 3; |
|||
} |
|||
} |
|||
|
|||
public override int ParameterDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 2; |
|||
} |
|||
} |
|||
|
|||
public override void ItemGradientByRef(Vector<double> x, int itemIndex, Vector<double> output) |
|||
{ |
|||
switch (itemIndex) |
|||
{ |
|||
case 0: |
|||
output[0] = 1; |
|||
output[1] = 0; |
|||
break; |
|||
case 1: |
|||
output[0] = 0; |
|||
output[1] = 1; |
|||
break; |
|||
case 2: |
|||
output[0] = x[1]; |
|||
output[1] = x[0]; |
|||
break; |
|||
default: |
|||
throw new ArgumentException("itemIndex must be <= 2"); |
|||
} |
|||
} |
|||
|
|||
public override void ItemHessianByRef(Vector<double> x, int itemIndex, Matrix<double> output) |
|||
{ |
|||
switch (itemIndex) |
|||
{ |
|||
case 0: |
|||
case 1: |
|||
output[0, 0] = 0; |
|||
output[0, 1] = 0; |
|||
output[1, 0] = 0; |
|||
output[1, 1] = 0; |
|||
break; |
|||
case 2: |
|||
output[0, 0] = 0; |
|||
output[0, 1] = 1; |
|||
output[1, 0] = 1; |
|||
output[1, 1] = 0; |
|||
break; |
|||
default: |
|||
throw new ArgumentException("itemIndex must be <= 2"); |
|||
} |
|||
} |
|||
|
|||
public override double ItemValue(Vector<double> x, int itemIndex) |
|||
{ |
|||
switch (itemIndex) |
|||
{ |
|||
case 0: |
|||
return x[0] - 1e6; |
|||
case 1: |
|||
return x[1] - 2e-6; |
|||
case 2: |
|||
return x[0] * x[1] - 2; |
|||
default: |
|||
throw new ArgumentException("itemIndex must be <= 2"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,98 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
using DenseVector = MathNet.Numerics.LinearAlgebra.Double.DenseVector; |
|||
using DenseMatrix = MathNet.Numerics.LinearAlgebra.Double.DenseMatrix; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions |
|||
{ |
|||
public class FreudensteinAndRothFunction : BaseTestFunction |
|||
{ |
|||
|
|||
public static IEnumerable<TestCase> TestCases |
|||
{ |
|||
get |
|||
{ |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new FreudensteinAndRothFunction(), |
|||
InitialGuess = new double[] { 0.5, -2 }, |
|||
MinimizingPoint = new double[] { 5, 4 }, |
|||
MinimalValue = 0, |
|||
CaseName = "unbounded" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new FreudensteinAndRothFunction(), |
|||
InitialGuess = new double[] { 0.5, -2 }, |
|||
MinimizingPoint = new double[] {5, 4}, |
|||
MinimalValue = 0, |
|||
LowerBound = new double[] { -1000, -1000 }, |
|||
UpperBound = new double[] { 1000, 1000}, |
|||
CaseName = "loose bounds" |
|||
}; |
|||
} |
|||
} |
|||
|
|||
public override string Description { get { return "Freudenstein & Roth fun (MGH #2)"; } } |
|||
|
|||
public override int ParameterDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 2; |
|||
} |
|||
} |
|||
|
|||
public override int ItemDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 2; |
|||
} |
|||
} |
|||
|
|||
public override double ItemValue(Vector<double> x, int itemIndex) |
|||
{ |
|||
if (itemIndex == 0) |
|||
return -13 + x[0] + ((5 - x[1]) * x[1] - 2) * x[1]; |
|||
else |
|||
return -29 + x[0] + ((x[1] + 1) * x[1] - 14) * x[1]; |
|||
} |
|||
|
|||
public override void ItemGradientByRef(Vector<double> x, int itemIndex, Vector<double> output) |
|||
{ |
|||
if (itemIndex == 0) |
|||
{ |
|||
output[0] = 1; |
|||
output[1] = -2 + (5 - 2 * x[1]) * x[1] + (5 - x[1]) * x[1]; |
|||
} |
|||
else |
|||
{ |
|||
output[0] = 1; |
|||
output[1] = -14 + x[1] * (1 + x[1]) + x[1] * (1 + 2 * x[1]); |
|||
} |
|||
} |
|||
|
|||
public override void ItemHessianByRef(Vector<double> x, int itemIndex, Matrix<double> output) |
|||
{ |
|||
if (itemIndex == 0) |
|||
{ |
|||
output[0, 0] = 0; |
|||
output[0, 1] = 0; |
|||
output[1, 0] = 0; |
|||
output[1, 1] = 10 - 6 * x[1]; |
|||
} |
|||
else |
|||
{ |
|||
output[0, 0] = 0; |
|||
output[0, 1] = 0; |
|||
output[1, 0] = 0; |
|||
output[1, 1] = 2 + 6 * x[1]; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,178 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions |
|||
{ |
|||
public class HelicalValleyFunction : BaseTestFunction |
|||
{ |
|||
public static IEnumerable<TestCase> TestCases |
|||
{ |
|||
get |
|||
{ |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new HelicalValleyFunction(), |
|||
InitialGuess = new double[] { -1, 0, 0 }, |
|||
MinimalValue = 0, |
|||
MinimizingPoint = new double[] { 1, 0, 0 }, |
|||
CaseName = "unbounded" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new HelicalValleyFunction(), |
|||
InitialGuess = new double[] { -1, 0, 0 }, |
|||
MinimalValue = 0, |
|||
MinimizingPoint = new double[] { 1, 0, 0 }, |
|||
LowerBound = new double[] { -1000, -1000, -1000 }, |
|||
UpperBound = new double[] { 1000, 1000, 1000 }, |
|||
CaseName = "loose bounds" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new HelicalValleyFunction(), |
|||
InitialGuess = new double[] { -1, 0, 0 }, |
|||
MinimalValue = 0.99042212, |
|||
LowerBound = new double[] { -100, -1, -1 }, |
|||
UpperBound = new double[] { 0.8, 1, 1 }, |
|||
CaseName = "tight bounds" |
|||
}; |
|||
} |
|||
} |
|||
|
|||
public override string Description |
|||
{ |
|||
get |
|||
{ |
|||
return "Helical valley fun (MGH #7)"; |
|||
} |
|||
} |
|||
|
|||
public override int ItemDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 3; |
|||
} |
|||
} |
|||
|
|||
public override int ParameterDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 3; |
|||
} |
|||
} |
|||
|
|||
public override void ItemGradientByRef(Vector<double> x, int itemIndex, Vector<double> output) |
|||
{ |
|||
switch (itemIndex) |
|||
{ |
|||
case 0: |
|||
output[0] = -100 * theta10(x[0], x[1]); |
|||
output[1] = -100 * theta01(x[0], x[1]); |
|||
output[2] = 10; |
|||
break; |
|||
case 1: |
|||
output[0] = (10 * x[0]) / Math.Sqrt(x[0]*x[0] + x[1]*x[1]); |
|||
output[1] = (10 * x[1]) / Math.Sqrt(x[0]*x[0] + x[1]*x[1]); |
|||
output[2] = 0; |
|||
break; |
|||
case 2: |
|||
output[0] = 0; |
|||
output[1] = 0; |
|||
output[2] = 1; |
|||
break; |
|||
default: |
|||
throw new ArgumentException("itemIndex must be <= 2"); |
|||
} |
|||
} |
|||
|
|||
public override void ItemHessianByRef(Vector<double> x, int itemIndex, Matrix<double> output) |
|||
{ |
|||
switch (itemIndex) |
|||
{ |
|||
case 0: |
|||
output[0, 0] = -100 * theta20(x[0], x[1]); |
|||
output[0, 1] = -100 * theta11(x[0], x[1]); |
|||
output[0, 2] = 0; |
|||
output[1, 0] = -100 * theta11(x[0], x[1]); |
|||
output[1, 1] = -100 * theta02(x[0], x[1]); |
|||
output[1, 2] = 0; |
|||
output[2, 0] = 0; |
|||
output[2, 1] = 0; |
|||
output[2, 2] = 0; |
|||
break; |
|||
case 1: |
|||
output[0, 0] = (10 * x[1]*x[1]) / Math.Pow(x[0]*x[0] + x[1]*x[1],1.5); |
|||
output[0, 1] = (-10 * x[0] * x[1]) / Math.Pow(x[0]*x[0] + x[1]*x[1],1.5); |
|||
output[0, 2] = 0; |
|||
output[1, 0] = (-10 * x[0] * x[1]) / Math.Pow(x[0] * x[0] + x[1] * x[1], 1.5); |
|||
output[1, 1] = (10 * x[0]*x[0]) / Math.Pow(x[0] * x[0] + x[1] * x[1], 1.5); |
|||
output[1, 2] = 0; |
|||
output[2, 0] = 0; |
|||
output[2, 1] = 0; |
|||
output[2, 2] = 0; |
|||
break; |
|||
case 2: |
|||
for (int ii = 0; ii < 2; ++ii) |
|||
for (int jj = 0; jj < 2; ++jj) |
|||
output[ii, jj] = 0; |
|||
break; |
|||
default: |
|||
throw new ArgumentException("itemIndex must be <= 2"); |
|||
} |
|||
} |
|||
|
|||
private static double theta(double x1, double x2) |
|||
{ |
|||
if (x1 >= 0) |
|||
return 0.5 * Math.Atan(x2 / x1) / Math.PI; |
|||
else |
|||
return 0.5 * Math.Atan(x2 / x1) / Math.PI + 0.5; |
|||
} |
|||
|
|||
private static double theta10(double x1, double x2) |
|||
{ |
|||
return -(x2 / (2 * Math.PI * Math.Pow(x1,2) + 2 * Math.PI * Math.Pow(x2,2))); |
|||
} |
|||
|
|||
private static double theta01(double x1, double x2) |
|||
{ |
|||
return x1 / (2 * Math.PI * x1*x1 + 2 * Math.PI * x2*x2); |
|||
} |
|||
|
|||
private static double theta20(double x1,double x2) |
|||
{ |
|||
return (x1 * x2) / (Math.PI * Math.Pow(x1 * x1 + x2 * x2, 2)); |
|||
} |
|||
|
|||
private static double theta11(double x1, double x2) |
|||
{ |
|||
return (-x1 * x1 + x2 * x2) / (2 * Math.PI * Math.Pow(x1 * x1 + x2 * x2, 2)); |
|||
} |
|||
|
|||
private static double theta02(double x1, double x2) |
|||
{ |
|||
return -((x1 * x2) / (Math.PI * Math.Pow(x1*x1 + x2*x2, 2))); |
|||
} |
|||
|
|||
public override double ItemValue(Vector<double> x, int itemIndex) |
|||
{ |
|||
switch (itemIndex) |
|||
{ |
|||
case 0: |
|||
return 10 * (x[2] - 10 * theta(x[0], x[1])); |
|||
case 1: |
|||
return 10 * (Math.Sqrt(x[0] * x[0] + x[1] * x[1]) - 1); |
|||
case 2: |
|||
return x[2]; |
|||
default: |
|||
throw new ArgumentException("itemIndex must be <= 2"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
using DenseVector = MathNet.Numerics.LinearAlgebra.Double.DenseVector; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions |
|||
{ |
|||
public class TestCase |
|||
{ |
|||
public string CaseName; |
|||
public ITestFunction Function; |
|||
public DenseVector InitialGuess; |
|||
public DenseVector LowerBound; |
|||
public DenseVector UpperBound; |
|||
public double MinimalValue; |
|||
public DenseVector MinimizingPoint; |
|||
|
|||
public bool IsBounded |
|||
{ |
|||
get |
|||
{ |
|||
return this.LowerBound != null && this.UpperBound != null; |
|||
} |
|||
} |
|||
|
|||
public bool IsUnbounded |
|||
{ |
|||
get |
|||
{ |
|||
return this.IsUnboundedOverride ?? this.LowerBound == null || this.UpperBound == null; |
|||
} |
|||
} |
|||
|
|||
public bool? IsUnboundedOverride; |
|||
|
|||
public string FullName |
|||
{ |
|||
get |
|||
{ |
|||
return $"{this.Function.Description} {this.CaseName}"; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public interface ITestFunction |
|||
{ |
|||
string Description { get; } |
|||
int ParameterDimension { get; } |
|||
int ItemDimension { get; } |
|||
|
|||
double ItemValue(Vector<double> x, int itemIndex); |
|||
Vector<double> ItemGradient(Vector<double> x, int itemIndex); |
|||
void ItemGradientByRef(Vector<double> x, int itemIndex, Vector<double> output); |
|||
Matrix<double> ItemHessian(Vector<double> x, int itemIndex); |
|||
void ItemHessianByRef(Vector<double> x, int itemIndex, Matrix<double> output); |
|||
|
|||
Matrix<double> Jacobian(Vector<double> x); |
|||
void JacobianbyRef(Vector<double> x, Matrix<double> output); |
|||
|
|||
double SsqValue(Vector<double> x); |
|||
Vector<double> SsqGradient(Vector<double> x); |
|||
void SsqGradientByRef(Vector<double> x, Vector<double> output); |
|||
Matrix<double> SsqHessian(Vector<double> x); |
|||
void SsqHessianByRef(Vector<double> x, Matrix<double> output); |
|||
} |
|||
} |
|||
@ -0,0 +1,102 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions |
|||
{ |
|||
public class JennrichAndSampsonFunction : BaseTestFunction |
|||
{ |
|||
private readonly int _m; |
|||
|
|||
public JennrichAndSampsonFunction(int itemDimension) |
|||
{ |
|||
if (itemDimension < 2) |
|||
throw new ArgumentException("itemDimension must be at least 2."); |
|||
_m = itemDimension; |
|||
} |
|||
|
|||
public static IEnumerable<TestCase> TestCases |
|||
{ |
|||
get |
|||
{ |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new JennrichAndSampsonFunction(10), |
|||
InitialGuess = new double[] { 0.3, 0.4 }, |
|||
MinimalValue = 124.362, |
|||
MinimizingPoint = new double[] { 0.2578, 0.2578 }, |
|||
CaseName = "unbounded" |
|||
}; |
|||
//yield return new TestCase()
|
|||
//{
|
|||
// Function = new JennrichAndSampsonFunction(10),
|
|||
// LowerBound = new double[] { 0.6, 0.5 },
|
|||
// UpperBound = new double[] { 10, 50 },
|
|||
// StartPoint = new double[] { 1.0, 1.0 },
|
|||
// MinimizingInput = null,
|
|||
// MinimizingValue = 0,
|
|||
// CaseName = "tight bounds"
|
|||
//};
|
|||
yield return new TestCase() |
|||
{ |
|||
Function = new JennrichAndSampsonFunction(10), |
|||
LowerBound = new double[] { -50, -50 }, |
|||
UpperBound = new double[] { 50, 50 }, |
|||
InitialGuess = new double[] { 0.3, 0.4 }, |
|||
MinimizingPoint = null, |
|||
MinimalValue = 0, |
|||
CaseName = "loose bounds" |
|||
}; |
|||
} |
|||
} |
|||
|
|||
public override string Description |
|||
{ |
|||
get |
|||
{ |
|||
return $"Jennrich & Sampson fun (MGH #6) (n={this.ItemDimension})"; |
|||
} |
|||
} |
|||
|
|||
public override int ItemDimension |
|||
{ |
|||
get |
|||
{ |
|||
return _m; |
|||
} |
|||
} |
|||
|
|||
public override int ParameterDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 2; |
|||
} |
|||
} |
|||
|
|||
public override void ItemGradientByRef(Vector<double> x, int itemIndex, Vector<double> output) |
|||
{ |
|||
int ii = itemIndex + 1; |
|||
output[0] = -(Math.Exp(ii * x[0]) * ii); |
|||
output[1] = -(Math.Exp(ii * x[1]) * ii); |
|||
} |
|||
|
|||
public override void ItemHessianByRef(Vector<double> x, int itemIndex, Matrix<double> output) |
|||
{ |
|||
int ii = itemIndex + 1; |
|||
output[0, 0] = -(Math.Exp(ii * x[0]) * ii*ii); |
|||
output[0, 1] = 0; |
|||
output[1, 0] = 0; |
|||
output[1, 1] = -(Math.Exp(ii * x[1]) * ii*ii); |
|||
} |
|||
|
|||
public override double ItemValue(Vector<double> x, int itemIndex) |
|||
{ |
|||
int ii = itemIndex + 1; |
|||
return 2 + 2 * ii - (Math.Exp(ii * x[0]) + Math.Exp(ii * x[1])); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,99 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions |
|||
{ |
|||
public class MeyerFunction : BaseTestFunction |
|||
{ |
|||
public static IEnumerable<TestCase> TestCases |
|||
{ |
|||
get |
|||
{ |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new MeyerFunction(), |
|||
InitialGuess = new double[] { 0.02, 4000, 250 }, |
|||
MinimalValue = 87.9458, |
|||
MinimizingPoint = null, |
|||
CaseName = "unbounded" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new MeyerFunction(), |
|||
InitialGuess = new double[] { 0.02, 4000, 250 }, |
|||
MinimalValue = 87.9458, |
|||
MinimizingPoint = null, |
|||
LowerBound = new double[] { -1e6, -1e6, -1e6 }, |
|||
UpperBound = new double[] { 1e6, 1e6, 1e6 }, |
|||
CaseName = "loose bounds" |
|||
}; |
|||
} |
|||
} |
|||
|
|||
public MeyerFunction() { } |
|||
|
|||
public override string Description |
|||
{ |
|||
get |
|||
{ |
|||
return "Meyer fun (MGH #10)"; |
|||
} |
|||
} |
|||
|
|||
public override int ItemDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 16; |
|||
} |
|||
} |
|||
|
|||
public override int ParameterDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 3; |
|||
} |
|||
} |
|||
|
|||
public override void ItemGradientByRef(Vector<double> x, int itemIndex, Vector<double> output) |
|||
{ |
|||
int ii = itemIndex + 1; |
|||
output[0] = Math.Exp(x[1] / (45.0 + 5 * ii + x[2])); |
|||
output[1] = (Math.Exp(x[1] / (45.0 + 5 * ii + x[2])) * x[0]) / (45 + 5 * ii + x[2]); |
|||
output[2] = -(Math.Exp(x[1] / (45.0 + 5 * ii + x[2])) * x[0] * x[1]) / Math.Pow(45 + 5 * ii + x[2], 2); |
|||
|
|||
} |
|||
|
|||
public override void ItemHessianByRef(Vector<double> x, int itemIndex, Matrix<double> output) |
|||
{ |
|||
var ii = itemIndex + 1; |
|||
|
|||
var t0 = (45.0 + 5 * ii + x[2]); |
|||
var t1 = Math.Exp(x[1] / t0); |
|||
|
|||
output[0, 0] = 0; |
|||
output[0, 1] = t1 / t0; |
|||
output[0, 2] = -t1 * x[1] / Math.Pow(t0, 2); |
|||
output[1, 0] = t1 / t0; |
|||
output[1, 1] = t1 * x[0] / Math.Pow(t0, 2); |
|||
output[1, 2] = -t1 * x[0] * (t0 + x[1]) / Math.Pow(t0, 3); |
|||
output[2, 0] = -t1 * x[1] / Math.Pow(t0, 2); |
|||
output[2, 1] = -t1 * x[0] * (t0 + x[1]) / Math.Pow(t0, 3); |
|||
output[2, 2] = t1 * x[0] * x[1] * (2*t0 + x[1]) / Math.Pow(t0, 4); |
|||
} |
|||
|
|||
private static readonly double[] y = { 34780, 28610, 23650, 19630, 16370, 13720, 11540, 9744, 8261, 7030, 6005, 5147, 4427, 3820, 3307, 2872 }; |
|||
|
|||
public override double ItemValue(Vector<double> x, int itemIndex) |
|||
{ |
|||
var ii = itemIndex + 1; |
|||
var t = 45.0 + 5 * ii; |
|||
return x[0] * Math.Exp(x[1] / (t + x[2])) - y[itemIndex]; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,111 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
using MathNet.Numerics.LinearAlgebra.Double; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions |
|||
{ |
|||
public class PowellBadlyScaledFunction : BaseTestFunction |
|||
{ |
|||
public static IEnumerable<TestCase> TestCases |
|||
{ |
|||
get |
|||
{ |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new PowellBadlyScaledFunction(), |
|||
InitialGuess = new double[] { 0, 1 }, |
|||
MinimizingPoint = new double[] { 1.098e-5, 9.106 }, |
|||
MinimalValue = 0, |
|||
CaseName = "unbounded" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new PowellBadlyScaledFunction(), |
|||
InitialGuess = new double[] { 0, 1 }, |
|||
MinimizingPoint = new double[] { 1.098e-5, 9.106 }, |
|||
MinimalValue = 0, |
|||
LowerBound = new double[] { -1000, -1000 }, |
|||
UpperBound = new double[] { 1000, 1000 }, |
|||
CaseName = "loose bounds" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new PowellBadlyScaledFunction(), |
|||
LowerBound = new double[] { 0, 1 }, |
|||
UpperBound = new double[] { 1, 9 }, |
|||
InitialGuess = new double[] { 0, 1 }, |
|||
MinimalValue = 0.15125900e-9, |
|||
CaseName = "tight bounds" |
|||
}; |
|||
} |
|||
} |
|||
|
|||
public override string Description |
|||
{ |
|||
get |
|||
{ |
|||
return "Powell badly scaled fun (MGH #3)"; |
|||
} |
|||
} |
|||
|
|||
public override int ItemDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 2; |
|||
} |
|||
} |
|||
|
|||
public override int ParameterDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 2; |
|||
} |
|||
} |
|||
|
|||
public override void ItemGradientByRef(Vector<double> x, int itemIndex, Vector<double> output) |
|||
{ |
|||
if (itemIndex == 0) |
|||
{ |
|||
output[0] = 10000 * x[1]; |
|||
output[1] = 10000 * x[0]; |
|||
} |
|||
else if (itemIndex == 1) |
|||
{ |
|||
output[0] = -Math.Exp(-x[0]); |
|||
output[1] = -Math.Exp(-x[1]); |
|||
} |
|||
} |
|||
|
|||
public override void ItemHessianByRef(Vector<double> x, int itemIndex, Matrix<double> output) |
|||
{ |
|||
if (itemIndex == 0) |
|||
{ |
|||
output[0, 0] = 0; |
|||
output[0, 1] = 10000; |
|||
output[1, 0] = 10000; |
|||
output[1, 1] = 0; |
|||
} |
|||
else |
|||
{ |
|||
output[0, 0] = Math.Exp(-x[0]); |
|||
output[0, 1] = 0; |
|||
output[1, 0] = 0; |
|||
output[1,1] = Math.Exp(-x[1]); |
|||
} |
|||
} |
|||
|
|||
public override double ItemValue(Vector<double> x, int itemIndex) |
|||
{ |
|||
if (itemIndex == 0) |
|||
return 10000.0 * x[0] * x[1] - 1; |
|||
else |
|||
return Math.Exp(-x[0]) + Math.Exp(-x[1]) - 1.0001; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,141 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions |
|||
{ |
|||
public class PowellSingularFunction : BaseTestFunction |
|||
{ |
|||
public static IEnumerable<TestCase> TestCases |
|||
{ |
|||
get |
|||
{ |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new PowellSingularFunction(), |
|||
InitialGuess = new double[] { 3, -1, 0, 1 }, |
|||
MinimalValue = 0, |
|||
MinimizingPoint = new double[] {0,0,0,0}, |
|||
CaseName = "unbounded" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new PowellSingularFunction(), |
|||
InitialGuess = new double[] { 3, -1, 0, 1 }, |
|||
MinimalValue = 0, |
|||
MinimizingPoint = new double[] { 0, 0, 0, 0 }, |
|||
LowerBound = new double[] {-1000, -1000, -1000, -1000}, |
|||
UpperBound = new double[] { 1000, 1000, 1000, 1000 }, |
|||
CaseName = "loose bounds" |
|||
}; |
|||
} |
|||
} |
|||
|
|||
|
|||
public PowellSingularFunction() { } |
|||
|
|||
public override string Description |
|||
{ |
|||
get |
|||
{ |
|||
return "Powell singular fun (MGH #13)"; |
|||
} |
|||
} |
|||
|
|||
public override int ItemDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 4; |
|||
} |
|||
} |
|||
|
|||
public override int ParameterDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 4; |
|||
} |
|||
} |
|||
|
|||
public override void ItemGradientByRef(Vector<double> x, int itemIndex, Vector<double> output) |
|||
{ |
|||
switch (itemIndex) |
|||
{ |
|||
case 0: |
|||
output[0] = 1; |
|||
output[1] = 10; |
|||
output[2] = 0; |
|||
output[3] = 0; |
|||
break; |
|||
case 1: |
|||
output[0] = 0; |
|||
output[1] = 0; |
|||
output[2] = Math.Sqrt(5); |
|||
output[3] = -Math.Sqrt(5); |
|||
break; |
|||
case 2: |
|||
output[0] = 0; |
|||
output[1] = 2*(x[1]-2*x[2]); |
|||
output[2] = -4*x[1] + 8*x[2]; |
|||
output[3] = 0; |
|||
break; |
|||
case 3: |
|||
output[0] = 2*Math.Sqrt(10)*(x[0] - x[3]); |
|||
output[1] = 0; |
|||
output[2] = 0; |
|||
output[3] = -2*Math.Sqrt(10)*(x[0] - x[3]); |
|||
break; |
|||
default: |
|||
throw new ArgumentException("itemIndex must be <= 3"); |
|||
} |
|||
} |
|||
|
|||
public override void ItemHessianByRef(Vector<double> x, int itemIndex, Matrix<double> output) |
|||
{ |
|||
for (int ii = 0; ii < 4; ++ii) |
|||
for (int jj = 0; jj < 4; ++jj) |
|||
output[ii, jj] = 0; |
|||
switch(itemIndex) |
|||
{ |
|||
case 0: |
|||
case 1: |
|||
break; |
|||
case 2: |
|||
output[1, 1] = 2; |
|||
output[1, 2] = -4; |
|||
output[2, 1] = -4; |
|||
output[2, 2] = 8; |
|||
break; |
|||
case 3: |
|||
output[0, 0] = 2 * Math.Sqrt(10); |
|||
output[0, 3] = -2 * Math.Sqrt(10); |
|||
output[3, 0] = -2 * Math.Sqrt(10); |
|||
output[3, 3] = 2 * Math.Sqrt(10); |
|||
break; |
|||
default: |
|||
throw new ArgumentException("itemIndex must be <= 3"); |
|||
} |
|||
} |
|||
|
|||
public override double ItemValue(Vector<double> x, int itemIndex) |
|||
{ |
|||
switch (itemIndex) |
|||
{ |
|||
case 0: |
|||
return x[0] + 10 * x[1]; |
|||
case 1: |
|||
return Math.Sqrt(5) * (x[2] - x[3]); |
|||
case 2: |
|||
return Math.Pow(x[1] - 2 * x[2], 2); |
|||
case 3: |
|||
return Math.Sqrt(10.0) * Math.Pow(x[0] - x[3], 2); |
|||
default: |
|||
throw new ArgumentException("itemIndex must be <= 3"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,156 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions |
|||
{ |
|||
public class RosenbrockFunction2 : BaseTestFunction |
|||
{ |
|||
public static IEnumerable<TestCase> TestCases |
|||
{ |
|||
get |
|||
{ |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new RosenbrockFunction2(), |
|||
InitialGuess = new double[] { -1.2, 1 }, |
|||
MinimizingPoint = new double[] { 1, 1 }, |
|||
MinimalValue = 0, |
|||
LowerBound = new double[] { -1000, -1000 }, |
|||
UpperBound = new double[] { 1000, 1000 }, |
|||
CaseName = "hard start", |
|||
IsUnboundedOverride = true |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new RosenbrockFunction2(), |
|||
InitialGuess = new double[] { 1.2, 1.2 }, |
|||
MinimizingPoint = new double[] { 1, 1 }, |
|||
MinimalValue = 0, |
|||
LowerBound = new double[] { -5, -5 }, |
|||
UpperBound = new double[] { 5, 5 }, |
|||
CaseName = "easy start" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new RosenbrockFunction2(), |
|||
InitialGuess = new double[] { -0.9, -0.5 }, |
|||
MinimizingPoint = new double[] { 1, 1 }, |
|||
MinimalValue = 0, |
|||
LowerBound = new double[] { -5, -5 }, |
|||
UpperBound = new double[] { 5, 5 }, |
|||
CaseName = "Overton start", |
|||
IsUnboundedOverride = true |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new RosenbrockFunction2(), |
|||
InitialGuess = new double[] { 1.2, 1.2 }, |
|||
MinimizingPoint = new double[] { 1, 1 }, |
|||
MinimalValue = 0, |
|||
LowerBound = new double[] { 1, -5 }, |
|||
UpperBound = new double[] { 5, 5 }, |
|||
CaseName = "easy one active bound" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new RosenbrockFunction2(), |
|||
InitialGuess = new double[] { 1.2, 1.2 }, |
|||
MinimizingPoint = new double[] { 1, 1 }, |
|||
MinimalValue = 0, |
|||
LowerBound = new double[] { 1, 1 }, |
|||
UpperBound = new double[] { 5, 5 }, |
|||
CaseName = "easy two active bounds" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new RosenbrockFunction2(), |
|||
InitialGuess = new double[] { 2.5, 2.5 }, |
|||
MinimizingPoint = new double[] { 2, 4 }, |
|||
MinimalValue = 1, |
|||
LowerBound = new double[] { 2, 2 }, |
|||
UpperBound = new double[] { 5, 5 }, |
|||
CaseName = "min on lower bound, not local" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new RosenbrockFunction2(), |
|||
InitialGuess = new double[] { -0.9, -0.5 }, |
|||
MinimizingPoint = new double[] { 0.5, 0.25 }, |
|||
MinimalValue = 0.25, |
|||
LowerBound = new double[] { -2, -2 }, |
|||
UpperBound = new double[] { 0.5, 0.5 }, |
|||
CaseName = "min on upper bound, not local" |
|||
}; |
|||
|
|||
|
|||
} |
|||
} |
|||
public RosenbrockFunction2() { } |
|||
|
|||
public override string Description |
|||
{ |
|||
get |
|||
{ |
|||
return "Rosenbrock fun (MGH #1)"; |
|||
} |
|||
} |
|||
|
|||
public override int ItemDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 2; |
|||
} |
|||
} |
|||
|
|||
public override int ParameterDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 2; |
|||
} |
|||
} |
|||
|
|||
public override void ItemGradientByRef(Vector<double> x, int itemIndex, Vector<double> output) |
|||
{ |
|||
if (itemIndex == 0) |
|||
{ |
|||
output[0] = -20 * x[0]; |
|||
output[1] = 10; |
|||
} else |
|||
{ |
|||
output[0] = -1; |
|||
output[1] = 0; |
|||
} |
|||
} |
|||
|
|||
public override void ItemHessianByRef(Vector<double> x, int itemIndex, Matrix<double> output) |
|||
{ |
|||
if (itemIndex == 0) |
|||
{ |
|||
output[0, 0] = -20; |
|||
output[0, 1] = 0; |
|||
output[1, 0] = 0; |
|||
output[1, 1] = 0; |
|||
} else |
|||
{ |
|||
output[0, 0] = 0; |
|||
output[0, 1] = 0; |
|||
output[1, 0] = 0; |
|||
output[1, 1] = 0; |
|||
} |
|||
} |
|||
|
|||
public override double ItemValue(Vector<double> x, int itemIndex) |
|||
{ |
|||
if (itemIndex == 0) |
|||
return 10 * (x[1] - x[0] * x[0]); |
|||
else |
|||
return 1 - x[0]; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,164 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
|
|||
namespace MathNet.Numerics.UnitTests.OptimizationTests.TestFunctions |
|||
{ |
|||
public class WoodFunction : BaseTestFunction |
|||
{ |
|||
public static IEnumerable<TestCase> TestCases |
|||
{ |
|||
get |
|||
{ |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new WoodFunction(), |
|||
InitialGuess = new double[] { -3, -1, -3, -1 }, |
|||
MinimalValue = 0, |
|||
MinimizingPoint = new double[] { 1, 1, 1, 1 }, |
|||
CaseName = "unbounded" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new WoodFunction(), |
|||
InitialGuess = new double[] { -3, -1, -3, -1 }, |
|||
MinimalValue = 0, |
|||
MinimizingPoint = new double[] { 1, 1, 1, 1 }, |
|||
LowerBound = new double[] { -1000, -1000, -1000, -1000 }, |
|||
UpperBound = new double[] { 1000, 1000, 1000, 1000 }, |
|||
CaseName = "loose bounds" |
|||
}; |
|||
yield return new TestCase() |
|||
{ |
|||
Function = new WoodFunction(), |
|||
InitialGuess = new double[] { -3, -1, -3, -1 }, |
|||
MinimalValue = 1.5567008, |
|||
MinimizingPoint = null, |
|||
LowerBound = new double[] { -100, -100, -100, -100 }, |
|||
UpperBound = new double[] { 0, 10, 100, 100 }, |
|||
CaseName = "tight bounds" |
|||
}; |
|||
} |
|||
} |
|||
|
|||
public WoodFunction() { } |
|||
|
|||
public override string Description |
|||
{ |
|||
get |
|||
{ |
|||
return "Wood fun (MGH #14)"; |
|||
} |
|||
} |
|||
|
|||
public override int ItemDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 6; |
|||
} |
|||
} |
|||
|
|||
public override int ParameterDimension |
|||
{ |
|||
get |
|||
{ |
|||
return 4; |
|||
} |
|||
} |
|||
|
|||
public override void ItemGradientByRef(Vector<double> x, int itemIndex, Vector<double> output) |
|||
{ |
|||
switch (itemIndex) |
|||
{ |
|||
case 0: |
|||
output[0] = -20 * x[0]; |
|||
output[1] = 10; |
|||
output[2] = 0; |
|||
output[3] = 0; |
|||
break; |
|||
case 1: |
|||
output[0] = -1; |
|||
output[1] = 0; |
|||
output[2] = 0; |
|||
output[3] = 0; |
|||
break; |
|||
case 2: |
|||
output[0] = 0; |
|||
output[1] = 0; |
|||
output[2] = -6 * Math.Sqrt(10) * x[2]; |
|||
output[3] = 3 * Math.Sqrt(10); |
|||
break; |
|||
case 3: |
|||
output[0] = 0; |
|||
output[1] = 0; |
|||
output[2] = -1; |
|||
output[3] = 0; |
|||
break; |
|||
case 4: |
|||
output[0] = 0; |
|||
output[1] = Math.Sqrt(10); |
|||
output[2] = 0; |
|||
output[3] = Math.Sqrt(10); |
|||
break; |
|||
case 5: |
|||
output[0] = 0; |
|||
output[1] = 1.0 / Math.Sqrt(10); |
|||
output[2] = 0; |
|||
output[3] = -1.0 / Math.Sqrt(10); |
|||
break; |
|||
default: |
|||
throw new ArgumentException("itemIndex must be <= 5"); |
|||
} |
|||
} |
|||
|
|||
public override void ItemHessianByRef(Vector<double> x, int itemIndex, Matrix<double> output) |
|||
{ |
|||
for (int ii = 0; ii < 4; ++ii) |
|||
for (int jj = 0; jj < 4; ++jj) |
|||
output[ii, jj] = 0; |
|||
switch (itemIndex) |
|||
{ |
|||
case 0: |
|||
output[0, 0] = -20; |
|||
break; |
|||
case 1: |
|||
break; |
|||
case 2: |
|||
output[2, 2] = -6 * Math.Sqrt(10); |
|||
break; |
|||
case 3: |
|||
case 4: |
|||
case 5: |
|||
break; |
|||
default: |
|||
throw new ArgumentException("itemIndex must be <= 5"); |
|||
|
|||
} |
|||
} |
|||
|
|||
public override double ItemValue(Vector<double> x, int itemIndex) |
|||
{ |
|||
switch (itemIndex) |
|||
{ |
|||
case 0: |
|||
return 10 * (x[1] - x[0] * x[0]); |
|||
case 1: |
|||
return 1 - x[0]; |
|||
case 2: |
|||
return Math.Sqrt(90) * (x[3] - x[2] * x[2]); |
|||
case 3: |
|||
return 1 - x[2]; |
|||
case 4: |
|||
return Math.Sqrt(10) * (x[1] + x[3] - 2); |
|||
case 5: |
|||
return (x[1] - x[3]) / Math.Sqrt(10); |
|||
default: |
|||
throw new ArgumentException("itemIndex must be <= 5"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue