diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj
index 9c7227b9..580bbe0d 100644
--- a/src/Numerics/Numerics.csproj
+++ b/src/Numerics/Numerics.csproj
@@ -118,6 +118,12 @@
+
+
+
+
+
+
diff --git a/src/Numerics/Optimization/ObjectiveFunction.cs b/src/Numerics/Optimization/ObjectiveFunction.cs
new file mode 100644
index 00000000..e3a1d577
--- /dev/null
+++ b/src/Numerics/Optimization/ObjectiveFunction.cs
@@ -0,0 +1,65 @@
+using System;
+using MathNet.Numerics.LinearAlgebra;
+using MathNet.Numerics.Optimization.ObjectiveFunctions;
+
+namespace MathNet.Numerics.Optimization
+{
+ public static class ObjectiveFunction
+ {
+ ///
+ /// Objective function where neither Gradient nor Hessian is available.
+ ///
+ public static IObjectiveFunction Value(Func, double> function)
+ {
+ return new ValueObjectiveFunction(function);
+ }
+
+ ///
+ /// Objective function where the Gradient is available. Greedy evaluation.
+ ///
+ public static IObjectiveFunction Gradient(Func, Tuple>> function)
+ {
+ return new GradientObjectiveFunction(function);
+ }
+
+ ///
+ /// Objective function where the Gradient is available. Lazy evaluation.
+ ///
+ public static IObjectiveFunction Gradient(Func, double> function, Func, Vector> gradient)
+ {
+ return new LazyObjectiveFunction(function, gradient: gradient);
+ }
+
+ ///
+ /// Objective function where the Hessian is available. Greedy evaluation.
+ ///
+ public static IObjectiveFunction Hessian(Func, Tuple>> function)
+ {
+ return new HessianObjectiveFunction(function);
+ }
+
+ ///
+ /// Objective function where the Hessian is available. Lazy evaluation.
+ ///
+ public static IObjectiveFunction Hessian(Func, double> function, Func, Matrix> hessian)
+ {
+ return new LazyObjectiveFunction(function, hessian: hessian);
+ }
+
+ ///
+ /// Objective function where both Gradient and Hessian are available. Greedy evaluation.
+ ///
+ public static IObjectiveFunction GradientHessian(Func, Tuple, Matrix>> function)
+ {
+ return new GradientHessianObjectiveFunction(function);
+ }
+
+ ///
+ /// Objective function where both Gradient and Hessian are available. Lazy evaluation.
+ ///
+ public static IObjectiveFunction GradientHessian(Func, double> function, Func, Vector> gradient, Func, Matrix> hessian)
+ {
+ return new LazyObjectiveFunction(function, gradient: gradient, hessian: hessian);
+ }
+ }
+}
diff --git a/src/Numerics/Optimization/ObjectiveFunctions/GradientHessianObjectiveFunction.cs b/src/Numerics/Optimization/ObjectiveFunctions/GradientHessianObjectiveFunction.cs
new file mode 100644
index 00000000..24d2a914
--- /dev/null
+++ b/src/Numerics/Optimization/ObjectiveFunctions/GradientHessianObjectiveFunction.cs
@@ -0,0 +1,57 @@
+using System;
+using MathNet.Numerics.LinearAlgebra;
+
+namespace MathNet.Numerics.Optimization.ObjectiveFunctions
+{
+ internal class GradientHessianObjectiveFunction : IObjectiveFunction
+ {
+ readonly Func, Tuple, Matrix>> _function;
+
+ public GradientHessianObjectiveFunction(Func, Tuple, Matrix>> function)
+ {
+ _function = function;
+ }
+
+ public IObjectiveFunction CreateNew()
+ {
+ return new GradientHessianObjectiveFunction(_function);
+ }
+
+ public IObjectiveFunction Fork()
+ {
+ // no need to deep-clone values since they are replaced on evaluation
+ return new GradientHessianObjectiveFunction(_function)
+ {
+ Point = Point,
+ Value = Value,
+ Gradient = Gradient,
+ Hessian = Hessian
+ };
+ }
+
+ public bool IsGradientSupported
+ {
+ get { return true; }
+ }
+
+ public bool IsHessianSupported
+ {
+ get { return true; }
+ }
+
+ public void EvaluateAt(Vector point)
+ {
+ Point = point;
+
+ var result = _function(point);
+ Value = result.Item1;
+ Gradient = result.Item2;
+ Hessian = result.Item3;
+ }
+
+ public Vector Point { get; private set; }
+ public double Value { get; private set; }
+ public Vector Gradient { get; private set; }
+ public Matrix Hessian { get; private set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Numerics/Optimization/ObjectiveFunctions/GradientObjectiveFunction.cs b/src/Numerics/Optimization/ObjectiveFunctions/GradientObjectiveFunction.cs
new file mode 100644
index 00000000..8d967f01
--- /dev/null
+++ b/src/Numerics/Optimization/ObjectiveFunctions/GradientObjectiveFunction.cs
@@ -0,0 +1,59 @@
+using System;
+using MathNet.Numerics.LinearAlgebra;
+
+namespace MathNet.Numerics.Optimization.ObjectiveFunctions
+{
+ internal class GradientObjectiveFunction : IObjectiveFunction
+ {
+ readonly Func, Tuple>> _function;
+
+ public GradientObjectiveFunction(Func, Tuple>> function)
+ {
+ _function = function;
+ }
+
+ public IObjectiveFunction CreateNew()
+ {
+ return new GradientObjectiveFunction(_function);
+ }
+
+ public IObjectiveFunction Fork()
+ {
+ // no need to deep-clone values since they are replaced on evaluation
+ return new GradientObjectiveFunction(_function)
+ {
+ Point = Point,
+ Value = Value,
+ Gradient = Gradient
+ };
+ }
+
+ public bool IsGradientSupported
+ {
+ get { return true; }
+ }
+
+ public bool IsHessianSupported
+ {
+ get { return false; }
+ }
+
+ public void EvaluateAt(Vector point)
+ {
+ Point = point;
+
+ var result = _function(point);
+ Value = result.Item1;
+ Gradient = result.Item2;
+ }
+
+ public Vector Point { get; private set; }
+ public double Value { get; private set; }
+ public Vector Gradient { get; private set; }
+
+ public Matrix Hessian
+ {
+ get { throw new NotSupportedException(); }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Numerics/Optimization/ObjectiveFunctions/HessianObjectiveFunction.cs b/src/Numerics/Optimization/ObjectiveFunctions/HessianObjectiveFunction.cs
new file mode 100644
index 00000000..54215980
--- /dev/null
+++ b/src/Numerics/Optimization/ObjectiveFunctions/HessianObjectiveFunction.cs
@@ -0,0 +1,59 @@
+using System;
+using MathNet.Numerics.LinearAlgebra;
+
+namespace MathNet.Numerics.Optimization.ObjectiveFunctions
+{
+ internal class HessianObjectiveFunction : IObjectiveFunction
+ {
+ readonly Func, Tuple>> _function;
+
+ public HessianObjectiveFunction(Func, Tuple>> function)
+ {
+ _function = function;
+ }
+
+ public IObjectiveFunction CreateNew()
+ {
+ return new HessianObjectiveFunction(_function);
+ }
+
+ public IObjectiveFunction Fork()
+ {
+ // no need to deep-clone values since they are replaced on evaluation
+ return new HessianObjectiveFunction(_function)
+ {
+ Point = Point,
+ Value = Value,
+ Hessian = Hessian
+ };
+ }
+
+ public bool IsGradientSupported
+ {
+ get { return false; }
+ }
+
+ public bool IsHessianSupported
+ {
+ get { return true; }
+ }
+
+ public void EvaluateAt(Vector point)
+ {
+ Point = point;
+
+ var result = _function(point);
+ Value = result.Item1;
+ Hessian = result.Item2;
+ }
+
+ public Vector Point { get; private set; }
+ public double Value { get; private set; }
+ public Matrix Hessian { get; private set; }
+
+ public Vector Gradient
+ {
+ get { throw new NotSupportedException(); }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Numerics/Optimization/ObjectiveFunctions/LazyObjectiveFunction.cs b/src/Numerics/Optimization/ObjectiveFunctions/LazyObjectiveFunction.cs
new file mode 100644
index 00000000..8b629cfd
--- /dev/null
+++ b/src/Numerics/Optimization/ObjectiveFunctions/LazyObjectiveFunction.cs
@@ -0,0 +1,112 @@
+using System;
+using MathNet.Numerics.LinearAlgebra;
+
+namespace MathNet.Numerics.Optimization.ObjectiveFunctions
+{
+ internal class LazyObjectiveFunction : IObjectiveFunction
+ {
+ readonly Func, double> _function;
+ readonly Func, Vector> _gradient;
+ readonly Func, Matrix> _hessian;
+
+ Vector _point;
+
+ bool _hasFunctionValue;
+ double _functionValue;
+
+ bool _hasGradientValue;
+ Vector _gradientValue;
+
+ bool _hasHessianValue;
+ Matrix _hessianValue;
+
+ public LazyObjectiveFunction(Func, double> function, Func, Vector> gradient = null, Func, Matrix> hessian = null)
+ {
+ _function = function;
+ _gradient = gradient;
+ _hessian = hessian;
+
+ IsGradientSupported = gradient != null;
+ IsHessianSupported = hessian != null;
+ }
+
+ public IObjectiveFunction CreateNew()
+ {
+ return new LazyObjectiveFunction(_function, _gradient, _hessian);
+ }
+
+ public IObjectiveFunction Fork()
+ {
+ // no need to deep-clone values since they are replaced on evaluation
+ return new LazyObjectiveFunction(_function, _gradient, _hessian)
+ {
+ _point = _point,
+ _hasFunctionValue = _hasFunctionValue,
+ _functionValue = _functionValue,
+ _hasGradientValue = _hasGradientValue,
+ _gradientValue = _gradientValue,
+ _hasHessianValue = _hasHessianValue,
+ _hessianValue = _hessianValue
+ };
+ }
+
+ public bool IsGradientSupported { get; private set; }
+ public bool IsHessianSupported { get; private set; }
+
+ public void EvaluateAt(Vector point)
+ {
+ _point = point;
+ _hasFunctionValue = false;
+ _hasGradientValue = false;
+ _hasHessianValue = false;
+
+ // don't keep references unnecessarily
+ _gradientValue = null;
+ _hessianValue = null;
+ }
+
+ public Vector Point
+ {
+ get { return _point; }
+ }
+
+ public double Value
+ {
+ get
+ {
+ if (!_hasFunctionValue)
+ {
+ _functionValue = _function(_point);
+ _hasFunctionValue = true;
+ }
+ return _functionValue;
+ }
+ }
+
+ public Vector Gradient
+ {
+ get
+ {
+ if (!_hasGradientValue)
+ {
+ _gradientValue = _gradient(_point);
+ _hasGradientValue = true;
+ }
+ return _gradientValue;
+ }
+ }
+
+ public Matrix Hessian
+ {
+ get
+ {
+ if (!_hasHessianValue)
+ {
+ _hessianValue = _hessian(_point);
+ _hasHessianValue = true;
+ }
+ return _hessianValue;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Numerics/Optimization/ObjectiveFunctions/ValueObjectiveFunction.cs b/src/Numerics/Optimization/ObjectiveFunctions/ValueObjectiveFunction.cs
new file mode 100644
index 00000000..19e75d74
--- /dev/null
+++ b/src/Numerics/Optimization/ObjectiveFunctions/ValueObjectiveFunction.cs
@@ -0,0 +1,59 @@
+using System;
+using MathNet.Numerics.LinearAlgebra;
+
+namespace MathNet.Numerics.Optimization.ObjectiveFunctions
+{
+ internal class ValueObjectiveFunction : IObjectiveFunction
+ {
+ readonly Func, double> _function;
+
+ public ValueObjectiveFunction(Func, double> function)
+ {
+ _function = function;
+ }
+
+ public IObjectiveFunction CreateNew()
+ {
+ return new ValueObjectiveFunction(_function);
+ }
+
+ public IObjectiveFunction Fork()
+ {
+ // no need to deep-clone values since they are replaced on evaluation
+ return new ValueObjectiveFunction(_function)
+ {
+ Point = Point,
+ Value = Value,
+ };
+ }
+
+ public bool IsGradientSupported
+ {
+ get { return false; }
+ }
+
+ public bool IsHessianSupported
+ {
+ get { return false; }
+ }
+
+ public void EvaluateAt(Vector point)
+ {
+ Point = point;
+ Value = _function(point);
+ }
+
+ public Vector Point { get; private set; }
+ public double Value { get; private set; }
+
+ public Matrix Hessian
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ public Vector Gradient
+ {
+ get { throw new NotSupportedException(); }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/UnitTests/OptimizationTests/TestNewtonMinimizer.cs b/src/UnitTests/OptimizationTests/TestNewtonMinimizer.cs
index d7f910d7..ad8bb32f 100644
--- a/src/UnitTests/OptimizationTests/TestNewtonMinimizer.cs
+++ b/src/UnitTests/OptimizationTests/TestNewtonMinimizer.cs
@@ -34,12 +34,10 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests
[TestFixture]
public class TestNewtonMinimizer
{
-
[Test]
public void FindMinimum_Rosenbrock_Easy()
{
- var obj = new RosenbrockObjectiveFunction();
-
+ var obj = ObjectiveFunction.GradientHessian(RosenbrockFunction.Value, RosenbrockFunction.Gradient, RosenbrockFunction.Hessian);
var solver = new NewtonMinimizer(1e-5, 1000);
var result = solver.FindMinimum(obj, new DenseVector(new[] { 1.2, 1.2 }));
@@ -50,7 +48,7 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests
[Test]
public void FindMinimum_Rosenbrock_Hard()
{
- var obj = new RosenbrockObjectiveFunction();
+ var obj = ObjectiveFunction.GradientHessian(point => Tuple.Create(RosenbrockFunction.Value(point), RosenbrockFunction.Gradient(point), RosenbrockFunction.Hessian(point)));
var solver = new NewtonMinimizer(1e-5, 1000);
var result = solver.FindMinimum(obj, new DenseVector(new[] { -1.2, 1.0 }));