diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj
index 2370e819..32dc2b7c 100644
--- a/src/Numerics/Numerics.csproj
+++ b/src/Numerics/Numerics.csproj
@@ -102,9 +102,9 @@
-
+
-
+
diff --git a/src/Numerics/Optimization/BaseObjectiveFunction.cs b/src/Numerics/Optimization/BaseObjectiveFunction.cs
deleted file mode 100644
index ed7f1331..00000000
--- a/src/Numerics/Optimization/BaseObjectiveFunction.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-using System;
-using MathNet.Numerics.LinearAlgebra;
-
-namespace MathNet.Numerics.Optimization
-{
- public abstract class BaseObjectiveFunction : IObjectiveFunction
- {
- [Flags]
- enum EvaluationStatus
- {
- None = 0,
- Value = 1,
- Gradient = 2,
- Hessian = 4
- }
-
- EvaluationStatus Status { get; set; }
-
- protected Vector PointRaw { get; set; }
- protected double ValueRaw { get; set; }
- protected Vector GradientRaw { get; set; }
- protected Matrix HessianRaw { get; set; }
-
- public bool IsGradientSupported { get; private set; }
- public bool IsHessianSupported { get; private set; }
-
- protected BaseObjectiveFunction(bool gradientSupported, bool hessianSupported)
- {
- Status = EvaluationStatus.None;
- IsGradientSupported = gradientSupported;
- IsHessianSupported = hessianSupported;
- }
-
- public Vector Point
- {
- get { return PointRaw; }
- }
-
- public void EvaluateAt(Vector point)
- {
- PointRaw = point;
- Status = EvaluationStatus.None;
- }
-
- public double Value
- {
- get
- {
- if (!Status.HasFlag(EvaluationStatus.Value))
- {
- SetValue();
- Status |= EvaluationStatus.Value;
- }
- return ValueRaw;
- }
- }
- public Vector Gradient
- {
- get
- {
- if (!Status.HasFlag(EvaluationStatus.Gradient))
- {
- SetGradient();
- Status |= EvaluationStatus.Gradient;
- }
- return GradientRaw;
- }
- }
- public Matrix Hessian
- {
- get
- {
- if (!Status.HasFlag(EvaluationStatus.Hessian))
- {
- SetHessian();
- Status |= EvaluationStatus.Hessian;
- }
- return HessianRaw;
- }
- }
-
- public abstract IObjectiveFunction CreateNew();
-
- public virtual IObjectiveFunction Fork()
- {
- BaseObjectiveFunction fork = (BaseObjectiveFunction)CreateNew();
- fork.PointRaw = PointRaw;
- fork.ValueRaw = ValueRaw;
- fork.GradientRaw = GradientRaw;
- fork.HessianRaw = HessianRaw;
- fork.Status = Status;
- return fork;
- }
-
- protected abstract void SetValue();
- protected abstract void SetGradient();
- protected abstract void SetHessian();
- }
-}
diff --git a/src/Numerics/Optimization/ObjectiveFunctions/InplaceObjectiveFunction.cs b/src/Numerics/Optimization/ObjectiveFunctions/InplaceObjectiveFunction.cs
deleted file mode 100644
index d2554dfb..00000000
--- a/src/Numerics/Optimization/ObjectiveFunctions/InplaceObjectiveFunction.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using MathNet.Numerics.LinearAlgebra;
-
-namespace MathNet.Numerics.Optimization.ObjectiveFunctions
-{
- public abstract class InplaceObjectiveFunction : IObjectiveFunction
- {
- Vector _point;
- double _functionValue;
- Vector _gradientValue;
- Matrix _hessianValue;
-
- protected InplaceObjectiveFunction(bool isGradientSupported, bool isHessianSupported)
- {
- IsGradientSupported = isGradientSupported;
- IsHessianSupported = isHessianSupported;
- }
-
- public abstract IObjectiveFunction CreateNew();
-
- public virtual IObjectiveFunction Fork()
- {
- // no need to deep-clone values since they are replaced on evaluation
- InplaceObjectiveFunction objective = (InplaceObjectiveFunction)CreateNew();
- objective._point = _point == null ? null : _point.Clone();
- objective._functionValue = _functionValue;
- objective._gradientValue = _gradientValue == null ? null : _gradientValue.Clone();
- objective._hessianValue = _hessianValue == null ? null : _hessianValue.Clone();
- return objective;
- }
-
- public bool IsGradientSupported { get; private set; }
- public bool IsHessianSupported { get; private set; }
-
- public void EvaluateAt(Vector point)
- {
- _point = point;
- EvaluateAt(_point, ref _functionValue, ref _gradientValue, ref _hessianValue);
- }
-
- protected abstract void EvaluateAt(Vector point, ref double value, ref Vector gradient, ref Matrix hessian);
-
- public Vector Point
- {
- get { return _point; }
- }
-
- public double Value
- {
- get { return _functionValue; }
- }
-
- public Vector Gradient
- {
- get { return _gradientValue; }
- }
-
- public Matrix Hessian
- {
- get { return _hessianValue; }
- }
- }
-}
diff --git a/src/Numerics/Optimization/ObjectiveFunctions/LazyObjectiveFunctionBase.cs b/src/Numerics/Optimization/ObjectiveFunctions/LazyObjectiveFunctionBase.cs
new file mode 100644
index 00000000..d8357772
--- /dev/null
+++ b/src/Numerics/Optimization/ObjectiveFunctions/LazyObjectiveFunctionBase.cs
@@ -0,0 +1,119 @@
+using MathNet.Numerics.LinearAlgebra;
+
+namespace MathNet.Numerics.Optimization.ObjectiveFunctions
+{
+ public abstract class LazyObjectiveFunctionBase : IObjectiveFunction
+ {
+ Vector _point;
+
+ bool _hasFunctionValue;
+ double _functionValue;
+
+ bool _hasGradientValue;
+ Vector _gradientValue;
+
+ bool _hasHessianValue;
+ Matrix _hessianValue;
+
+ protected LazyObjectiveFunctionBase(bool gradientSupported, bool hessianSupported)
+ {
+ IsGradientSupported = gradientSupported;
+ IsHessianSupported = hessianSupported;
+ }
+
+ public abstract IObjectiveFunction CreateNew();
+
+ public virtual IObjectiveFunction Fork()
+ {
+ // we need to deep-clone values since they may be updated inplace on evaluation
+ LazyObjectiveFunctionBase fork = (LazyObjectiveFunctionBase)CreateNew();
+ fork._point = _point == null ? null : _point.Clone();
+ fork._hasFunctionValue = _hasFunctionValue;
+ fork._functionValue = _functionValue;
+ fork._hasGradientValue = _hasGradientValue;
+ fork._gradientValue = _gradientValue == null ? null : _gradientValue.Clone(); ;
+ fork._hasHessianValue = _hasHessianValue;
+ fork._hessianValue = _hessianValue == null ? null : _hessianValue.Clone();
+ return fork;
+ }
+
+ 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;
+ }
+
+ protected abstract void EvaluateValue();
+
+ protected virtual void EvaluateGradient()
+ {
+ Gradient = null;
+ }
+
+ protected virtual void EvaluateHessian()
+ {
+ Hessian = null;
+ }
+
+ public Vector Point
+ {
+ get { return _point; }
+ }
+
+ public double Value
+ {
+ get
+ {
+ if (!_hasFunctionValue)
+ {
+ EvaluateValue();
+ }
+ return _functionValue;
+ }
+ protected set
+ {
+ _functionValue = value;
+ _hasFunctionValue = true;
+ }
+ }
+
+ public Vector Gradient
+ {
+ get
+ {
+ if (!_hasGradientValue)
+ {
+ EvaluateGradient();
+ }
+ return _gradientValue;
+ }
+ protected set
+ {
+ _gradientValue = value;
+ _hasGradientValue = true;
+ }
+ }
+
+ public Matrix Hessian
+ {
+ get
+ {
+ if (!_hasHessianValue)
+ {
+ EvaluateHessian();
+ }
+ return _hessianValue;
+ }
+ protected set
+ {
+ _hessianValue = value;
+ _hasHessianValue = true;
+ }
+ }
+ }
+}
diff --git a/src/Numerics/Optimization/ObjectiveFunctions/ObjectiveFunctionBase.cs b/src/Numerics/Optimization/ObjectiveFunctions/ObjectiveFunctionBase.cs
new file mode 100644
index 00000000..f212bcc0
--- /dev/null
+++ b/src/Numerics/Optimization/ObjectiveFunctions/ObjectiveFunctionBase.cs
@@ -0,0 +1,42 @@
+using MathNet.Numerics.LinearAlgebra;
+
+namespace MathNet.Numerics.Optimization.ObjectiveFunctions
+{
+ public abstract class ObjectiveFunctionBase : IObjectiveFunction
+ {
+ protected ObjectiveFunctionBase(bool isGradientSupported, bool isHessianSupported)
+ {
+ IsGradientSupported = isGradientSupported;
+ IsHessianSupported = isHessianSupported;
+ }
+
+ public abstract IObjectiveFunction CreateNew();
+
+ public virtual IObjectiveFunction Fork()
+ {
+ // we need to deep-clone values since they may be updated inplace on evaluation
+ ObjectiveFunctionBase objective = (ObjectiveFunctionBase)CreateNew();
+ objective.Point = Point == null ? null : Point.Clone();
+ objective.Value = Value;
+ objective.Gradient = Gradient == null ? null : Gradient.Clone();
+ objective.Hessian = Hessian == null ? null : Hessian.Clone();
+ return objective;
+ }
+
+ public bool IsGradientSupported { get; private set; }
+ public bool IsHessianSupported { get; private set; }
+
+ public void EvaluateAt(Vector point)
+ {
+ Point = point;
+ Evaluate();
+ }
+
+ protected abstract void Evaluate();
+
+ public Vector Point { get; private set; }
+ public double Value { get; protected set; }
+ public Vector Gradient { get; protected set; }
+ public Matrix Hessian { get; protected set; }
+ }
+}
diff --git a/src/UnitTests/OptimizationTests/TestNewtonMinimizer.cs b/src/UnitTests/OptimizationTests/TestNewtonMinimizer.cs
index 85912a65..772c07ad 100644
--- a/src/UnitTests/OptimizationTests/TestNewtonMinimizer.cs
+++ b/src/UnitTests/OptimizationTests/TestNewtonMinimizer.cs
@@ -1,5 +1,4 @@
using System;
-using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.LinearAlgebra.Double;
using MathNet.Numerics.Optimization;
using MathNet.Numerics.Optimization.ObjectiveFunctions;
@@ -7,47 +6,47 @@ using NUnit.Framework;
namespace MathNet.Numerics.UnitTests.OptimizationTests
{
- public class RosenbrockObjectiveFunction : BaseObjectiveFunction
+ public class LazyRosenbrockObjectiveFunction : LazyObjectiveFunctionBase
{
- public RosenbrockObjectiveFunction() : base(true, true) { }
+ public LazyRosenbrockObjectiveFunction() : base(true, true) { }
- protected override void SetValue()
+ public override IObjectiveFunction CreateNew()
{
- ValueRaw = RosenbrockFunction.Value(Point);
+ return new LazyRosenbrockObjectiveFunction();
}
- protected override void SetGradient()
+ protected override void EvaluateValue()
{
- GradientRaw = RosenbrockFunction.Gradient(Point);
+ Value = RosenbrockFunction.Value(Point);
}
- protected override void SetHessian()
+ protected override void EvaluateGradient()
{
- HessianRaw = RosenbrockFunction.Hessian(Point);
+ Gradient = RosenbrockFunction.Gradient(Point);
}
- public override IObjectiveFunction CreateNew()
+ protected override void EvaluateHessian()
{
- return new RosenbrockObjectiveFunction();
+ Hessian = RosenbrockFunction.Hessian(Point);
}
}
- public class InplaceRosenbrockObjectiveFunction : InplaceObjectiveFunction
+ public class RosenbrockObjectiveFunction : ObjectiveFunctionBase
{
- public InplaceRosenbrockObjectiveFunction() : base(true, true) { }
+ public RosenbrockObjectiveFunction() : base(true, true) { }
public override IObjectiveFunction CreateNew()
{
- return new InplaceRosenbrockObjectiveFunction();
+ return new RosenbrockObjectiveFunction();
}
- protected override void EvaluateAt(Vector point, ref double value, ref Vector gradient, ref Matrix hessian)
+ protected override void Evaluate()
{
- // here we could directly overwrite the existing matrices instead.
- // note: values must then be initialized manually here first, if null.
- value = RosenbrockFunction.Value(point);
- gradient = RosenbrockFunction.Gradient(point);
- hessian = RosenbrockFunction.Hessian(point);
+ // here we could directly overwrite the existing matrix cells instead.
+ // note: values must then be initialized manually first, if null.
+ Value = RosenbrockFunction.Value(Point);
+ Gradient = RosenbrockFunction.Gradient(Point);
+ Hessian = RosenbrockFunction.Hessian(Point);
}
}
@@ -79,7 +78,7 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests
[Test]
public void FindMinimum_Rosenbrock_Overton()
{
- var obj = new RosenbrockObjectiveFunction();
+ var obj = new LazyRosenbrockObjectiveFunction();
var solver = new NewtonMinimizer(1e-5, 1000);
var result = solver.FindMinimum(obj, new DenseVector(new[] { -0.9, -0.5 }));
@@ -90,7 +89,7 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests
[Test]
public void FindMinimum_Linesearch_Rosenbrock_Easy()
{
- var obj = new InplaceRosenbrockObjectiveFunction();
+ var obj = new RosenbrockObjectiveFunction();
var solver = new NewtonMinimizer(1e-5, 1000, true);
var result = solver.FindMinimum(obj, new DenseVector(new[] { 1.2, 1.2 }));
@@ -101,7 +100,7 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests
[Test]
public void FindMinimum_Linesearch_Rosenbrock_Hard()
{
- var obj = new RosenbrockObjectiveFunction();
+ var obj = new LazyRosenbrockObjectiveFunction();
var solver = new NewtonMinimizer(1e-5, 1000, true);
var result = solver.FindMinimum(obj, new DenseVector(new[] { -1.2, 1.0 }));
@@ -112,7 +111,7 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests
[Test]
public void FindMinimum_Linesearch_Rosenbrock_Overton()
{
- var obj = new RosenbrockObjectiveFunction();
+ var obj = new LazyRosenbrockObjectiveFunction();
var solver = new NewtonMinimizer(1e-5, 1000, true);
var result = solver.FindMinimum(obj, new DenseVector(new[] { -0.9, -0.5 }));