Browse Source

Optimization: (Lazy)ObjectiveFunction base classes

pull/391/head
Christoph Ruegg 11 years ago
parent
commit
330a577f19
  1. 4
      src/Numerics/Numerics.csproj
  2. 99
      src/Numerics/Optimization/BaseObjectiveFunction.cs
  3. 62
      src/Numerics/Optimization/ObjectiveFunctions/InplaceObjectiveFunction.cs
  4. 119
      src/Numerics/Optimization/ObjectiveFunctions/LazyObjectiveFunctionBase.cs
  5. 42
      src/Numerics/Optimization/ObjectiveFunctions/ObjectiveFunctionBase.cs
  6. 47
      src/UnitTests/OptimizationTests/TestNewtonMinimizer.cs

4
src/Numerics/Numerics.csproj

@ -102,9 +102,9 @@
<Compile Include="LinearAlgebra\Solvers\DelegateStopCriterion.cs" />
<Compile Include="LinearAlgebra\CreateVector.cs" />
<Compile Include="LinearRegression\Options.cs" />
<Compile Include="Optimization\BaseObjectiveFunction.cs" />
<Compile Include="Optimization\ObjectiveFunctions\LazyObjectiveFunctionBase.cs" />
<Compile Include="Optimization\Exceptions.cs" />
<Compile Include="Optimization\ObjectiveFunctions\InplaceObjectiveFunction.cs" />
<Compile Include="Optimization\ObjectiveFunctions\ObjectiveFunctionBase.cs" />
<Compile Include="Optimization\ObjectiveFunctions\LazyObjectiveFunction.cs" />
<Compile Include="Optimization\ObjectiveFunction.cs" />
<Compile Include="Optimization\ObjectiveFunctions\ValueObjectiveFunction.cs" />

99
src/Numerics/Optimization/BaseObjectiveFunction.cs

@ -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<double> PointRaw { get; set; }
protected double ValueRaw { get; set; }
protected Vector<double> GradientRaw { get; set; }
protected Matrix<double> 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<double> Point
{
get { return PointRaw; }
}
public void EvaluateAt(Vector<double> point)
{
PointRaw = point;
Status = EvaluationStatus.None;
}
public double Value
{
get
{
if (!Status.HasFlag(EvaluationStatus.Value))
{
SetValue();
Status |= EvaluationStatus.Value;
}
return ValueRaw;
}
}
public Vector<double> Gradient
{
get
{
if (!Status.HasFlag(EvaluationStatus.Gradient))
{
SetGradient();
Status |= EvaluationStatus.Gradient;
}
return GradientRaw;
}
}
public Matrix<double> 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();
}
}

62
src/Numerics/Optimization/ObjectiveFunctions/InplaceObjectiveFunction.cs

@ -1,62 +0,0 @@
using MathNet.Numerics.LinearAlgebra;
namespace MathNet.Numerics.Optimization.ObjectiveFunctions
{
public abstract class InplaceObjectiveFunction : IObjectiveFunction
{
Vector<double> _point;
double _functionValue;
Vector<double> _gradientValue;
Matrix<double> _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<double> point)
{
_point = point;
EvaluateAt(_point, ref _functionValue, ref _gradientValue, ref _hessianValue);
}
protected abstract void EvaluateAt(Vector<double> point, ref double value, ref Vector<double> gradient, ref Matrix<double> hessian);
public Vector<double> Point
{
get { return _point; }
}
public double Value
{
get { return _functionValue; }
}
public Vector<double> Gradient
{
get { return _gradientValue; }
}
public Matrix<double> Hessian
{
get { return _hessianValue; }
}
}
}

119
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<double> _point;
bool _hasFunctionValue;
double _functionValue;
bool _hasGradientValue;
Vector<double> _gradientValue;
bool _hasHessianValue;
Matrix<double> _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<double> 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<double> Point
{
get { return _point; }
}
public double Value
{
get
{
if (!_hasFunctionValue)
{
EvaluateValue();
}
return _functionValue;
}
protected set
{
_functionValue = value;
_hasFunctionValue = true;
}
}
public Vector<double> Gradient
{
get
{
if (!_hasGradientValue)
{
EvaluateGradient();
}
return _gradientValue;
}
protected set
{
_gradientValue = value;
_hasGradientValue = true;
}
}
public Matrix<double> Hessian
{
get
{
if (!_hasHessianValue)
{
EvaluateHessian();
}
return _hessianValue;
}
protected set
{
_hessianValue = value;
_hasHessianValue = true;
}
}
}
}

42
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<double> point)
{
Point = point;
Evaluate();
}
protected abstract void Evaluate();
public Vector<double> Point { get; private set; }
public double Value { get; protected set; }
public Vector<double> Gradient { get; protected set; }
public Matrix<double> Hessian { get; protected set; }
}
}

47
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<double> point, ref double value, ref Vector<double> gradient, ref Matrix<double> 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 }));

Loading…
Cancel
Save