diff --git a/src/Numerics.Tests/FitTests.cs b/src/Numerics.Tests/FitTests.cs
index c17c225f..9b7aa949 100644
--- a/src/Numerics.Tests/FitTests.cs
+++ b/src/Numerics.Tests/FitTests.cs
@@ -339,5 +339,25 @@ namespace MathNet.Numerics.UnitTests
Assert.AreEqual(-0.467791 * z, resf(z), 1e-4);
}
}
+
+ [Test]
+ public void FitsCurveToBestLine()
+ {
+ // Mathematica: Fit[{{1,4.986},{2,2.347},{3,2.061},{4,-2.995},{5,-2.352},{6,-5.782}}, {1, x}, x]
+ // -> 7.01013 - 2.08551*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, (m, s, t) => m + s*t, 1.0, -1.0, 1e-12);
+ Assert.AreEqual(7.01013, resp.Item1, 1e-4);
+ Assert.AreEqual(-2.08551, resp.Item2, 1e-4);
+
+ var resf = Fit.CurveFunc(x, y, (m, s, t) => m + s * t, 1.0, -1.0, 1e-12);
+ foreach (var z in Enumerable.Range(-3, 10))
+ {
+ Assert.AreEqual(7.01013 - 2.08551 * z, resf(z), 1e-4);
+ }
+ }
}
}
diff --git a/src/Numerics/Fit.cs b/src/Numerics/Fit.cs
index 8d65c986..2802bdcb 100644
--- a/src/Numerics/Fit.cs
+++ b/src/Numerics/Fit.cs
@@ -345,13 +345,51 @@ namespace MathNet.Numerics
}
///
- /// Least-Squares fitting the points (x,y) to a line y : x -> a+b*x,
- /// returning a function y' for the best fitting line.
+ /// Non-linear least-squares fitting the points (x,y) to an arbitrary function y : x -> f(p0, p1, x),
+ /// returning its best fitting parameter p0 and p1.
+ ///
+ public static Tuple Curve(double[] x, double[] y, Func f, double initialGuess0, double initialGuess1, double tolerance = 1e-8, int maxIterations = 1000)
+ {
+ return FindMinimum.OfFunction((p0, p1) => Distance.Euclidean(Generate.Map(x, t => f(p0, p1, t)), y), initialGuess0, initialGuess1, tolerance, maxIterations);
+ }
+
+ ///
+ /// Non-linear least-squares fitting the points (x,y) to an arbitrary function y : x -> f(p0, p1, p2, x),
+ /// returning its best fitting parameter p0, p1 and p2.
+ ///
+ public static Tuple Curve(double[] x, double[] y, Func f, double initialGuess0, double initialGuess1, double initialGuess2, double tolerance = 1e-8, int maxIterations = 1000)
+ {
+ return FindMinimum.OfFunction((p0, p1, p2) => Distance.Euclidean(Generate.Map(x, t => f(p0, p1, p2, t)), y), initialGuess0, initialGuess1, initialGuess2, tolerance, maxIterations);
+ }
+
+ ///
+ /// Non-linear least-squares fitting the points (x,y) to an arbitrary function y : x -> f(p, x),
+ /// returning a function y' for the best fitting curve.
///
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);
}
+
+ ///
+ /// Non-linear least-squares fitting the points (x,y) to an arbitrary function y : x -> f(p0, p1, x),
+ /// returning a function y' for the best fitting curve.
+ ///
+ public static Func CurveFunc(double[] x, double[] y, Func f, double initialGuess0, double initialGuess1, double tolerance = 1e-8, int maxIterations = 1000)
+ {
+ var parameters = Curve(x, y, f, initialGuess0, initialGuess1, tolerance, maxIterations);
+ return z => f(parameters.Item1, parameters.Item2, z);
+ }
+
+ ///
+ /// Non-linear least-squares fitting the points (x,y) to an arbitrary function y : x -> f(p0, p1, p2, x),
+ /// returning a function y' for the best fitting curve.
+ ///
+ public static Func CurveFunc(double[] x, double[] y, Func f, double initialGuess0, double initialGuess1, double initialGuess2, double tolerance = 1e-8, int maxIterations = 1000)
+ {
+ var parameters = Curve(x, y, f, initialGuess0, initialGuess1, initialGuess2, tolerance, maxIterations);
+ return z => f(parameters.Item1, parameters.Item2, parameters.Item3, z);
+ }
}
}