diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index a478aab5..370d2a0d 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -122,8 +122,6 @@ - - diff --git a/src/Numerics/Optimization/BaseEvaluation.cs b/src/Numerics/Optimization/BaseEvaluation.cs index fa19f5e8..c1a703bc 100644 --- a/src/Numerics/Optimization/BaseEvaluation.cs +++ b/src/Numerics/Optimization/BaseEvaluation.cs @@ -9,15 +9,34 @@ namespace MathNet.Numerics.Optimization { public abstract class BaseEvaluation : IEvaluation { - public EvaluationStatus Status { get; set; } - public Vector Point { get; set; } - public double ValueRaw { get; set; } - public Vector GradientRaw { get; set; } - public Matrix HessianRaw { get; set; } - - protected BaseEvaluation() + public EvaluationStatus Status { get; protected set; } + + protected Vector PointRaw { get; set; } + protected double ValueRaw { get; set; } + protected Vector GradientRaw { get; set; } + protected Matrix HessianRaw { get; set; } + + public bool GradientSupported { get; private set; } + public bool HessianSupported { get; private set; } + + protected BaseEvaluation(bool gradient_supported, bool hessian_supported) { Status = EvaluationStatus.None; + this.GradientSupported = gradient_supported; + this.HessianSupported = hessian_supported; + } + + public Vector Point + { + get + { + return this.PointRaw; + } + set + { + this.PointRaw = value; + this.Status = EvaluationStatus.None; + } } public double Value @@ -57,14 +76,9 @@ namespace MathNet.Numerics.Optimization } } - public void Reset(Vector new_point) - { - this.Point = new_point; - this.Status = EvaluationStatus.None; - } - protected abstract void setValue(); protected abstract void setGradient(); protected abstract void setHessian(); + public abstract IEvaluation CreateNew(); } } diff --git a/src/Numerics/Optimization/BaseObjectiveFunction.cs b/src/Numerics/Optimization/BaseObjectiveFunction.cs deleted file mode 100644 index 5cd5f68f..00000000 --- a/src/Numerics/Optimization/BaseObjectiveFunction.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace MathNet.Numerics.Optimization -{ - public class BaseObjectiveFunction : IObjectiveFunction where T : IEvaluation - { - public BaseObjectiveFunction(bool gradient_supported, bool hessian_supported) - { - _gradient_supported = gradient_supported; - _hessian_supported = hessian_supported; - } - - private bool _gradient_supported; - private bool _hessian_supported; - - public bool GradientSupported - { - get { return _gradient_supported; } - } - - public bool HessianSupported - { - get { return _hessian_supported; } - } - - public void Evaluate(LinearAlgebra.Vector point, IEvaluation output) - { - output.Reset(point); - } - - public virtual IEvaluation CreateEvaluationObject() - { - return default(T); - } - } -} diff --git a/src/Numerics/Optimization/IEvaluation.cs b/src/Numerics/Optimization/IEvaluation.cs index 9150d5fd..9ee1a83a 100644 --- a/src/Numerics/Optimization/IEvaluation.cs +++ b/src/Numerics/Optimization/IEvaluation.cs @@ -12,17 +12,14 @@ namespace MathNet.Numerics.Optimization public interface IEvaluation { Vector Point { get; set; } - EvaluationStatus Status { get; set; } + IEvaluation CreateNew(); // Used by algorithm + bool GradientSupported { get; } + bool HessianSupported { get; } + EvaluationStatus Status { get; } double Value { get; } Vector Gradient { get; } Matrix Hessian { get; } - - // Used by ObjectiveFunction - void Reset(Vector new_point); - double ValueRaw { get; set; } - Vector GradientRaw { get; set; } - Matrix HessianRaw { get; set; } } } diff --git a/src/Numerics/Optimization/IObjectiveFunction.cs b/src/Numerics/Optimization/IObjectiveFunction.cs deleted file mode 100644 index cd553ac2..00000000 --- a/src/Numerics/Optimization/IObjectiveFunction.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using MathNet.Numerics.LinearAlgebra; - -namespace MathNet.Numerics.Optimization -{ - public interface IObjectiveFunction - { - bool GradientSupported { get; } - bool HessianSupported { get; } - - IEvaluation CreateEvaluationObject(); - void Evaluate(Vector point, IEvaluation output); - } -} diff --git a/src/Numerics/Optimization/IUnconstrainedMinimizer.cs b/src/Numerics/Optimization/IUnconstrainedMinimizer.cs index d7200b01..37ac4928 100644 --- a/src/Numerics/Optimization/IUnconstrainedMinimizer.cs +++ b/src/Numerics/Optimization/IUnconstrainedMinimizer.cs @@ -8,7 +8,7 @@ namespace MathNet.Numerics.Optimization { public interface IUnconstrainedMinimizer { - MinimizationOutput FindMinimum(IObjectiveFunction objective, Vector initial_guess); + MinimizationOutput FindMinimum(IEvaluation objective, Vector initial_guess); } } diff --git a/src/Numerics/Optimization/Implementation/NullEvaluation.cs b/src/Numerics/Optimization/Implementation/NullEvaluation.cs index fcc31c4b..521419f3 100644 --- a/src/Numerics/Optimization/Implementation/NullEvaluation.cs +++ b/src/Numerics/Optimization/Implementation/NullEvaluation.cs @@ -10,7 +10,7 @@ namespace MathNet.Numerics.Optimization.Implementation public class NullEvaluation : BaseEvaluation { public NullEvaluation(Vector point) - : base() + : base(false, false) { this.Point = point; } @@ -28,5 +28,10 @@ namespace MathNet.Numerics.Optimization.Implementation { throw new NotImplementedException(); } + + public override IEvaluation CreateNew() + { + throw new NotImplementedException(); + } } } diff --git a/src/Numerics/Optimization/Implementation/ObjectiveChecker.cs b/src/Numerics/Optimization/Implementation/ObjectiveChecker.cs index 3aa0d052..af6ef93d 100644 --- a/src/Numerics/Optimization/Implementation/ObjectiveChecker.cs +++ b/src/Numerics/Optimization/Implementation/ObjectiveChecker.cs @@ -8,16 +8,21 @@ namespace MathNet.Numerics.Optimization.Implementation { public class CheckedEvaluation : IEvaluation { - private ObjectiveChecker Checker; public IEvaluation InnerEvaluation { get; private set; } private bool ValueChecked; private bool GradientChecked; private bool HessianChecked; + public Action ValueChecker { get; private set; } + public Action GradientChecker { get; private set; } + public Action HessianChecker { get; private set; } - public CheckedEvaluation(ObjectiveChecker checker, IEvaluation evaluation) + + public CheckedEvaluation(IEvaluation objective, Action value_checker, Action gradient_checker, Action hessian_checker) { - this.Checker = checker; - this.InnerEvaluation = evaluation; + this.InnerEvaluation = objective; + this.ValueChecker = value_checker; + this.GradientChecker = gradient_checker; + this.HessianChecker = hessian_checker; } public Vector Point @@ -32,34 +37,6 @@ namespace MathNet.Numerics.Optimization.Implementation { return this.InnerEvaluation.Status; } - set - { - this.InnerEvaluation.Status = value; - } - } - - public double ValueRaw - { - get - { - return this.InnerEvaluation.Value; - } - set - { - this.InnerEvaluation.ValueRaw = value; - } - } - - public Vector GradientRaw - { - get { return this.InnerEvaluation.GradientRaw; } - set { this.InnerEvaluation.GradientRaw = value; } - } - - public Matrix HessianRaw - { - get { return this.InnerEvaluation.HessianRaw; } - set { this.InnerEvaluation.HessianRaw = value; } } public double Value @@ -78,7 +55,7 @@ namespace MathNet.Numerics.Optimization.Implementation { throw new EvaluationException("Objective function evaluation failed.", this.InnerEvaluation, e); } - this.Checker.ValueChecker(this.InnerEvaluation); + this.ValueChecker(this.InnerEvaluation); this.ValueChecked = true; } return this.InnerEvaluation.Value; @@ -101,7 +78,7 @@ namespace MathNet.Numerics.Optimization.Implementation { throw new EvaluationException("Objective gradient evaluation failed.", this.InnerEvaluation, e); } - this.Checker.GradientChecker(this.InnerEvaluation); + this.GradientChecker(this.InnerEvaluation); this.GradientChecked = true; } return this.InnerEvaluation.Gradient; @@ -124,60 +101,26 @@ namespace MathNet.Numerics.Optimization.Implementation { throw new EvaluationException("Objective hessian evaluation failed.", this.InnerEvaluation, e); } - this.Checker.HessianChecker(InnerEvaluation); + this.HessianChecker(InnerEvaluation); this.HessianChecked = true; } return this.InnerEvaluation.Hessian; } } - public void Reset(Vector new_point) + public IEvaluation CreateNew() { - this.InnerEvaluation.Reset(new_point); - } - } - - public class ObjectiveChecker : IObjectiveFunction - { - public IObjectiveFunction InnerObjective { get; private set; } - public Action ValueChecker { get; private set; } - public Action GradientChecker { get; private set; } - public Action HessianChecker { get; private set; } - - public ObjectiveChecker(IObjectiveFunction objective, Action value_checker, Action gradient_checker, Action hessian_checker) - { - this.InnerObjective = objective; - this.ValueChecker = value_checker; - this.GradientChecker = gradient_checker; - this.HessianChecker = hessian_checker; + return new CheckedEvaluation(this.InnerEvaluation, this.ValueChecker, this.GradientChecker, this.HessianChecker); } public bool GradientSupported { - get { return this.InnerObjective.GradientSupported; } + get { return this.InnerEvaluation.GradientSupported; } } public bool HessianSupported { - get { return this.InnerObjective.HessianSupported; } - } - - public void Evaluate(Vector point, IEvaluation output) - { - try - { - this.InnerObjective.Evaluate(point, output); - } - catch (Exception e) - { - throw new EvaluationException("Objective evaluation failed.", new NullEvaluation(point), e); - } - } - - - public IEvaluation CreateEvaluationObject() - { - return this.InnerObjective.CreateEvaluationObject(); + get { return this.InnerEvaluation.HessianSupported; } } } } diff --git a/src/Numerics/Optimization/Implementation/WeakWolfeLineSearch.cs b/src/Numerics/Optimization/Implementation/WeakWolfeLineSearch.cs index 605c424b..5a6642b5 100644 --- a/src/Numerics/Optimization/Implementation/WeakWolfeLineSearch.cs +++ b/src/Numerics/Optimization/Implementation/WeakWolfeLineSearch.cs @@ -23,11 +23,11 @@ namespace MathNet.Numerics.Optimization.Implementation } // Implemented following http://www.math.washington.edu/~burke/crs/408/lectures/L9-weak-Wolfe.pdf - public LineSearchOutput FindConformingStep(IObjectiveFunction objective, IEvaluation starting_point, Vector search_direction, double initial_step) + public LineSearchOutput FindConformingStep(IEvaluation objective, IEvaluation starting_point, Vector search_direction, double initial_step) { - if (!(objective is ObjectiveChecker)) - objective = new ObjectiveChecker(objective, this.ValidateValue, this.ValidateGradient, null); + if (!(objective is CheckedEvaluation)) + objective = new CheckedEvaluation(objective, this.ValidateValue, this.ValidateGradient, null); double lower_bound = 0.0; double upper_bound = Double.PositiveInfinity; @@ -39,11 +39,11 @@ namespace MathNet.Numerics.Optimization.Implementation double initial_dd = search_direction * initial_gradient; int ii; - IEvaluation candidate_eval = objective.CreateEvaluationObject(); + IEvaluation candidate_eval = objective.CreateNew(); MinimizationOutput.ExitCondition reason_for_exit = MinimizationOutput.ExitCondition.None; for (ii = 0; ii < this.MaximumIterations; ++ii) { - objective.Evaluate(starting_point.Point + search_direction * step, candidate_eval); + candidate_eval.Point = starting_point.Point + search_direction * step; double step_dd = search_direction * candidate_eval.Gradient; diff --git a/src/Numerics/Optimization/NewtonMinimizer.cs b/src/Numerics/Optimization/NewtonMinimizer.cs index 810c859f..5f17d738 100644 --- a/src/Numerics/Optimization/NewtonMinimizer.cs +++ b/src/Numerics/Optimization/NewtonMinimizer.cs @@ -21,7 +21,7 @@ namespace MathNet.Numerics.Optimization this.UseLineSearch = use_line_search; } - public MinimizationOutput FindMinimum(IObjectiveFunction objective, Vector initial_guess) + public MinimizationOutput FindMinimum(IEvaluation objective, Vector initial_guess) { if (!objective.GradientSupported) throw new IncompatibleObjectiveException("Gradient not supported in objective function, but required for Newton minimization."); @@ -29,11 +29,11 @@ namespace MathNet.Numerics.Optimization if (!objective.HessianSupported) throw new IncompatibleObjectiveException("Hessian not supported in objective function, but required for Newton minimization."); - if (!(objective is ObjectiveChecker)) - objective = new ObjectiveChecker(objective, this.ValidateObjective, this.ValidateGradient, this.ValidateHessian); + if (!(objective is CheckedEvaluation)) + objective = new CheckedEvaluation(objective, this.ValidateObjective, this.ValidateGradient, this.ValidateHessian); - IEvaluation initial_eval = objective.CreateEvaluationObject(); - objective.Evaluate(initial_guess, initial_eval); + IEvaluation initial_eval = objective.CreateNew(); + initial_eval.Point = initial_guess; // Check that we're not already done if (this.ExitCriteriaSatisfied(initial_guess, initial_eval.Gradient)) @@ -81,7 +81,7 @@ namespace MathNet.Numerics.Optimization } else { - objective.Evaluate(candidate_point.Point + search_direction, candidate_point); + candidate_point.Point = candidate_point.Point + search_direction; } tmp_line_search = false; diff --git a/src/UnitTests/OptimizationTests/TestNewtonMinimizer.cs b/src/UnitTests/OptimizationTests/TestNewtonMinimizer.cs index fd6b6779..2fbca71e 100644 --- a/src/UnitTests/OptimizationTests/TestNewtonMinimizer.cs +++ b/src/UnitTests/OptimizationTests/TestNewtonMinimizer.cs @@ -11,9 +11,9 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests { public class RosenbrockEvaluation : BaseEvaluation { - public const bool SupportsGradient = true; - public const bool SupportsHessian = true; - + public RosenbrockEvaluation() + : base(true, true) { } + protected override void setValue() { this.ValueRaw = RosenbrockFunction.Value(this.Point); @@ -28,6 +28,11 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests { this.HessianRaw = RosenbrockFunction.Hessian(this.Point); } + + public override IEvaluation CreateNew() + { + return new RosenbrockEvaluation(); + } } [TestFixture] @@ -37,7 +42,7 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests [Test] public void FindMinimum_Rosenbrock_Easy() { - var obj = new BaseObjectiveFunction(RosenbrockEvaluation.SupportsGradient, RosenbrockEvaluation.SupportsHessian); + var obj = new RosenbrockEvaluation(); var solver = new NewtonMinimizer(1e-5, 1000); var result = solver.FindMinimum(obj, new MathNet.Numerics.LinearAlgebra.Double.DenseVector(new double[] { 1.2, 1.2 })); @@ -49,7 +54,7 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests [Test] public void FindMinimum_Rosenbrock_Hard() { - var obj = new BaseObjectiveFunction(RosenbrockEvaluation.SupportsGradient, RosenbrockEvaluation.SupportsHessian); + var obj = new RosenbrockEvaluation(); var solver = new NewtonMinimizer(1e-5, 1000); var result = solver.FindMinimum(obj, new MathNet.Numerics.LinearAlgebra.Double.DenseVector(new double[] { -1.2, 1.0 })); @@ -60,7 +65,7 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests [Test] public void FindMinimum_Rosenbrock_Overton() { - var obj = new BaseObjectiveFunction(RosenbrockEvaluation.SupportsGradient, RosenbrockEvaluation.SupportsHessian); + var obj = new RosenbrockEvaluation(); var solver = new NewtonMinimizer(1e-5, 1000); var result = solver.FindMinimum(obj, new MathNet.Numerics.LinearAlgebra.Double.DenseVector(new double[] { -0.9, -0.5 })); @@ -71,7 +76,7 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests [Test] public void FindMinimum_Linesearch_Rosenbrock_Easy() { - var obj = new BaseObjectiveFunction(RosenbrockEvaluation.SupportsGradient, RosenbrockEvaluation.SupportsHessian); + var obj = new RosenbrockEvaluation(); var solver = new NewtonMinimizer(1e-5, 1000, true); var result = solver.FindMinimum(obj, new MathNet.Numerics.LinearAlgebra.Double.DenseVector(new double[] { 1.2, 1.2 })); @@ -82,7 +87,7 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests [Test] public void FindMinimum_Linesearch_Rosenbrock_Hard() { - var obj = new BaseObjectiveFunction(RosenbrockEvaluation.SupportsGradient, RosenbrockEvaluation.SupportsHessian); + var obj = new RosenbrockEvaluation(); var solver = new NewtonMinimizer(1e-5, 1000, true); var result = solver.FindMinimum(obj, new MathNet.Numerics.LinearAlgebra.Double.DenseVector(new double[] { -1.2, 1.0 })); @@ -93,7 +98,7 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests [Test] public void FindMinimum_Linesearch_Rosenbrock_Overton() { - var obj = new BaseObjectiveFunction(RosenbrockEvaluation.SupportsGradient, RosenbrockEvaluation.SupportsHessian); + var obj = new RosenbrockEvaluation(); var solver = new NewtonMinimizer(1e-5, 1000, true); var result = solver.FindMinimum(obj, new MathNet.Numerics.LinearAlgebra.Double.DenseVector(new double[] { -0.9, -0.5 }));