diff --git a/MathNet.Numerics.sln.DotSettings b/MathNet.Numerics.sln.DotSettings
index 5bbf624a..14b3d43d 100644
--- a/MathNet.Numerics.sln.DotSettings
+++ b/MathNet.Numerics.sln.DotSettings
@@ -81,5 +81,6 @@ OTHER DEALINGS IN THE SOFTWARE.
True
True
True
+ True
diff --git a/src/Numerics.Tests/FitTests.cs b/src/Numerics.Tests/FitTests.cs
index e4e4eb70..c17c225f 100644
--- a/src/Numerics.Tests/FitTests.cs
+++ b/src/Numerics.Tests/FitTests.cs
@@ -320,5 +320,24 @@ namespace MathNet.Numerics.UnitTests
Assert.AreEqual(4.02159*Math.Sin(z) - 1.46962*Math.Cos(z) - 0.287476, resf(z), 1e-4);
}
}
+
+ [Test]
+ public void FitsCurveToBestLineThroughOrigin()
+ {
+ // Mathematica: Fit[{{1,4.986},{2,2.347},{3,2.061},{4,-2.995},{5,-2.352},{6,-5.782}}, {x}, x]
+ // -> -0.467791 x
+
+ var x = Enumerable.Range(1, 6).Select(Convert.ToDouble).ToArray();
+ var y = new[] { 4.986, 2.347, 2.061, -2.995, -2.352, -5.782 };
+
+ var resp = Fit.Curve(x, y, (s,t) => s*t, -1.0);
+ Assert.AreEqual(-0.467791, resp, 1e-4);
+
+ var resf = Fit.CurveFunc(x, y, (s, t) => s * t, -1.0, 1e-10);
+ foreach (var z in Enumerable.Range(-3, 10))
+ {
+ Assert.AreEqual(-0.467791 * z, resf(z), 1e-4);
+ }
+ }
}
}
diff --git a/src/Numerics/FindMinimum.cs b/src/Numerics/FindMinimum.cs
index b37bcfcd..76b02944 100644
--- a/src/Numerics/FindMinimum.cs
+++ b/src/Numerics/FindMinimum.cs
@@ -46,6 +46,17 @@ namespace MathNet.Numerics
return result.MinimizingPoint;
}
+ ///
+ /// Find vector x that minimizes the function f(x) using the Nelder-Mead Simplex algorithm.
+ /// For more options and diagnostics consider to use directly.
+ ///
+ public static double OfScalarFunction(Func function, double initialGuess, double tolerance = 1e-8, int maxIterations = 1000)
+ {
+ var objective = ObjectiveFunction.Value(v => function(v[0]));
+ var result = NelderMeadSimplex.Minimum(objective, CreateVector.Dense(new[] { initialGuess }), tolerance, maxIterations);
+ return result.MinimizingPoint[0];
+ }
+
///
/// Find vector x that minimizes the function f(x) using the Nelder-Mead Simplex algorithm.
/// For more options and diagnostics consider to use directly.
diff --git a/src/Numerics/Fit.cs b/src/Numerics/Fit.cs
index 34d8a0cf..8116a5f5 100644
--- a/src/Numerics/Fit.cs
+++ b/src/Numerics/Fit.cs
@@ -32,6 +32,7 @@ using System.Linq;
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.LinearRegression;
using MathNet.Numerics.Providers.LinearAlgebra;
+using MathNet.Numerics.Statistics;
namespace MathNet.Numerics
{
@@ -334,5 +335,24 @@ namespace MathNet.Numerics
var parameters = LinearGeneric(x, y, method, functions);
return z => functions.Zip(parameters, (f, p) => p * f(z)).Sum();
}
+
+ ///
+ /// Non-linear least-squares fitting the points (x,y) to an arbitrary function y : x -> f(p, x),
+ /// returning its best fitting parameter p.
+ ///
+ public static double Curve(double[] x, double[] y, Func f, double initialGuess, double tolerance = 1e-8, int maxIterations = 1000)
+ {
+ return FindMinimum.OfScalarFunction(p => Distance.Euclidean(Generate.Map(x, t => f(p, t)), y), initialGuess, tolerance, maxIterations);
+ }
+
+ ///
+ /// Least-Squares fitting the points (x,y) to a line y : x -> a+b*x,
+ /// returning a function y' for the best fitting line.
+ ///
+ public static Func CurveFunc(double[] x, double[] y, Func f, double initialGuess, double tolerance = 1e-8, int maxIterations = 1000)
+ {
+ var parameters = Curve(x, y, f, initialGuess, tolerance, maxIterations);
+ return z => f(parameters, z);
+ }
}
}