diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj
index 77e1579d..27b0246a 100644
--- a/src/Numerics/Numerics.csproj
+++ b/src/Numerics/Numerics.csproj
@@ -121,7 +121,6 @@
-
@@ -263,6 +262,12 @@
+
+
+
+
+
+
diff --git a/src/Numerics/Optimization/BFGS.cs b/src/Numerics/Optimization/BFGS.cs
new file mode 100644
index 00000000..7b9942d2
--- /dev/null
+++ b/src/Numerics/Optimization/BFGS.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MathNet.Numerics.Optimization
+{
+ class BFGS
+ {
+ }
+}
diff --git a/src/Numerics/Optimization/ConjugateGradientMinimizer.cs b/src/Numerics/Optimization/ConjugateGradientMinimizer.cs
new file mode 100644
index 00000000..44611707
--- /dev/null
+++ b/src/Numerics/Optimization/ConjugateGradientMinimizer.cs
@@ -0,0 +1,78 @@
+using System;
+using MathNet.Numerics.LinearAlgebra;
+using MathNet.Numerics.Optimization.LineSearch;
+
+namespace MathNet.Numerics.Optimization
+{
+ public class ConjugateGradientMinimizer
+ {
+ public double GradientTolerance { get; set; }
+ public int MaximumIterations { get; set; }
+
+ public ConjugateGradientMinimizer(double gradientTolerance, int maximumIterations)
+ {
+ this.GradientTolerance = gradientTolerance;
+ this.MaximumIterations = maximumIterations;
+ }
+
+ public MinimizationResult FindMinimum(IObjectiveFunction objective, Vector initialGuess)
+ {
+ if (!objective.IsGradientSupported)
+ throw new Exception("Gradient not supported in objective function, but required for ConjugateGradient minimization.");
+
+ objective.EvaluateAt(initialGuess);
+ var gradient = objective.Gradient;
+ ValidateGradient(gradient, initialGuess);
+
+ // Check that we're not already done
+ if (ExitCriteriaSatisfied(initialGuess, gradient))
+ return new MinimizationResult(objective, 0, MinimizationResult.ExitCondition.AbsoluteGradient);
+
+ // Set up line search algorithm
+ var lineSearcher = new WeakWolfeLineSearch(1e-4, 0.1, 1e-4, 1000);
+
+ // First step
+ var steepestDirection = -gradient;
+ var searchDirection = steepestDirection;
+ var result = lineSearcher.FindConformingStep(objective, searchDirection, 1.0);
+ objective = result.FunctionInfoAtMinimum;
+ ValidateGradient(objective.Gradient, objective.Point);
+
+ // Subsequent steps
+ int iterations = 1;
+ while (!ExitCriteriaSatisfied(objective.Point, objective.Gradient) && iterations < MaximumIterations)
+ {
+ var previousSteepestDirection = steepestDirection;
+ steepestDirection = -objective.Gradient;
+ var searchDirectionAdjuster = steepestDirection * (steepestDirection - previousSteepestDirection) / (previousSteepestDirection * previousSteepestDirection);
+ searchDirection = steepestDirection + searchDirectionAdjuster * previousSteepestDirection;
+ result = lineSearcher.FindConformingStep(objective, searchDirection, 1.0);
+
+ objective = result.FunctionInfoAtMinimum;
+ iterations += 1;
+ }
+
+ return new MinimizationResult(objective, iterations, MinimizationResult.ExitCondition.AbsoluteGradient);
+ }
+
+ private bool ExitCriteriaSatisfied(Vector candidatePoint, Vector gradient)
+ {
+ return gradient.Norm(2.0) < GradientTolerance;
+ }
+
+ private void ValidateGradient(Vector gradient, Vector input)
+ {
+ foreach (var x in gradient)
+ {
+ if (Double.IsNaN(x) || Double.IsInfinity(x))
+ throw new Exception("Non-finite gradient returned.");
+ }
+ }
+
+ private void ValidateObjective(double objective, Vector input)
+ {
+ if (Double.IsNaN(objective) || Double.IsInfinity(objective))
+ throw new Exception("Non-finite objective function returned.");
+ }
+ }
+}
diff --git a/src/Numerics/Optimization/GoldenSectionMinimizer.cs b/src/Numerics/Optimization/GoldenSectionMinimizer.cs
new file mode 100644
index 00000000..516cceeb
--- /dev/null
+++ b/src/Numerics/Optimization/GoldenSectionMinimizer.cs
@@ -0,0 +1,6 @@
+namespace MathNet.Numerics.Optimization
+{
+ class GoldenSectionMinimizer
+ {
+ }
+}
diff --git a/src/Numerics/Optimization/LineSearch/StrongWolfeLineSearch.cs b/src/Numerics/Optimization/LineSearch/StrongWolfeLineSearch.cs
new file mode 100644
index 00000000..236c63c9
--- /dev/null
+++ b/src/Numerics/Optimization/LineSearch/StrongWolfeLineSearch.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MathNet.Numerics.Optimization
+{
+ class StrongWolfeLineSearch
+ {
+ }
+}
diff --git a/src/Numerics/Optimization/OptimizationResult.cs b/src/Numerics/Optimization/OptimizationResult.cs
new file mode 100644
index 00000000..512e11d9
--- /dev/null
+++ b/src/Numerics/Optimization/OptimizationResult.cs
@@ -0,0 +1,8 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MathNet.Numerics.Optimization
+{
+}
diff --git a/src/UnitTests/OptimizationTests/TestConjugateGradientMinimizer.cs b/src/UnitTests/OptimizationTests/TestConjugateGradientMinimizer.cs
new file mode 100644
index 00000000..b06f410c
--- /dev/null
+++ b/src/UnitTests/OptimizationTests/TestConjugateGradientMinimizer.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using NUnit.Framework;
+
+using MathNet.Numerics.Optimization;
+
+namespace MathNet.Numerics.UnitTests.OptimizationTests
+{
+ [TestFixture]
+ public class TestConjugateGradientMinimizer
+ {
+
+ [Test]
+ public void FindMinimum_Rosenbrock_Easy()
+ {
+ var obj = new SimpleObjectiveFunction(RosenbrockFunction.Value, RosenbrockFunction.Gradient);
+ var solver = new ConjugateGradientMinimizer(1e-5, 100);
+ var result = solver.FindMinimum(obj, new MathNet.Numerics.LinearAlgebra.Double.DenseVector(new double[]{1.2,1.2}));
+ Assert.That(result.MinimizingPoint[0], Is.EqualTo(1.0));
+ Assert.That(result.MinimizingPoint[1], Is.EqualTo(1.0));
+ }
+
+ [Test]
+ public void FindMinimum_Rosenbrock_Hard()
+ {
+
+ }
+ }
+}
diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj
index 92d33f59..455b070b 100644
--- a/src/UnitTests/UnitTests.csproj
+++ b/src/UnitTests/UnitTests.csproj
@@ -371,6 +371,12 @@
+
+
+
+
+
+
@@ -423,6 +429,11 @@
+
+
+
+
+