diff --git a/src/FSharp/Fit.fs b/src/FSharp/Fit.fs
index f14dfce9..2fd45512 100644
--- a/src/FSharp/Fit.fs
+++ b/src/FSharp/Fit.fs
@@ -40,8 +40,8 @@ module Fit =
let private tofs (f:Func<_,_>) = fun a -> f.Invoke(a)
/// Least-Squares fitting the points (x,y) to a line y : x -> a+b*x,
- /// returning its best fitting parameters as [a, b] array.
- let line x y = let p = Fit.Line(x,y) in (p.[0],p.[1])
+ /// returning its best fitting parameters as (a, b) tuple.
+ let line x y = Fit.Line(x,y)
/// Least-Squares fitting the points (x,y) to a line y : x -> a+b*x,
/// returning a function y' for the best fitting line.
diff --git a/src/Numerics/Fit.cs b/src/Numerics/Fit.cs
index d0bedb42..f68006b4 100644
--- a/src/Numerics/Fit.cs
+++ b/src/Numerics/Fit.cs
@@ -31,7 +31,7 @@
using System;
using System.Linq;
using MathNet.Numerics.LinearAlgebra.Double;
-using MathNet.Numerics.Properties;
+using MathNet.Numerics.LinearRegression;
namespace MathNet.Numerics
{
@@ -42,44 +42,12 @@ namespace MathNet.Numerics
{
///
/// Least-Squares fitting the points (x,y) to a line y : x -> a+b*x,
- /// returning its best fitting parameters as [a, b] array.
+ /// returning its best fitting parameters as [a, b] array,
+ /// where a is the intercept and b the slope.
///
- public static double[] Line(double[] x, double[] y)
+ public static Tuple Line(double[] x, double[] y)
{
- if (x == null) throw new ArgumentNullException("x");
- if (y == null) throw new ArgumentNullException("y");
- if (x.Length != y.Length) throw new ArgumentException(Resources.ArgumentVectorsSameLength);
- if (x.Length <= 1) throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 2));
-
- // First Pass: Mean (Less robust but faster than ArrayStatistics.Mean)
- double mx = 0.0;
- double my = 0.0;
- for (int i = 0; i < x.Length; i++)
- {
- mx += x[i];
- my += y[i];
- }
- mx /= x.Length;
- my /= y.Length;
-
- // Second Pass: Covariance/Variance
- double covariance = 0.0;
- double variance = 0.0;
- for (int i = 0; i < x.Length; i++)
- {
- double diff = x[i] - mx;
- covariance += diff*(y[i] - my);
- variance += diff*diff;
- }
-
- var b = covariance/variance;
- return new[] {my - b*mx, b};
-
- // General Solution:
- //return DenseMatrix
- // .OfColumns(x.Length, 2, new[] {DenseVector.Create(x.Length, i => 1.0), new DenseVector(x)})
- // .QR(QRMethod.Thin).Solve(new DenseVector(y))
- // .ToArray();
+ return SimpleRegression.Fit(x, y);
}
///
@@ -88,9 +56,9 @@ namespace MathNet.Numerics
///
public static Func LineFunc(double[] x, double[] y)
{
- var parameters = Line(x, y);
- double a = parameters[0], b = parameters[1];
- return z => a + b*z;
+ var parameters = SimpleRegression.Fit(x, y);
+ double intercept = parameters.Item1, slope = parameters.Item2;
+ return z => intercept + slope*z;
}
///
@@ -99,10 +67,8 @@ namespace MathNet.Numerics
///
public static double[] Polynomial(double[] x, double[] y, int order)
{
- return DenseMatrix
- .OfColumns(x.Length, order + 1, Enumerable.Range(0, order + 1).Select(j => DenseVector.Create(x.Length, i => Math.Pow(x[i], j))))
- .QR().Solve(new DenseVector(y))
- .ToArray();
+ var design = DenseMatrix.OfColumns(x.Length, order + 1, Enumerable.Range(0, order + 1).Select(j => DenseVector.Create(x.Length, i => Math.Pow(x[i], j))));
+ return MultipleRegression.QR(design, new DenseVector(y)).ToArray();
}
///
@@ -121,10 +87,8 @@ namespace MathNet.Numerics
///
public static double[] LinearCombination(double[] x, double[] y, params Func[] functions)
{
- return DenseMatrix
- .OfColumns(x.Length, functions.Length, functions.Select(f => DenseVector.Create(x.Length, i => f(x[i]))))
- .QR().Solve(new DenseVector(y))
- .ToArray();
+ var design = DenseMatrix.OfColumns(x.Length, functions.Length, functions.Select(f => DenseVector.Create(x.Length, i => f(x[i]))));
+ return MultipleRegression.QR(design, new DenseVector(y)).ToArray();
}
///
@@ -143,10 +107,7 @@ namespace MathNet.Numerics
///
public static double[] LinearMultiDim(double[][] x, double[] y, params Func[] functions)
{
- return DenseMatrix
- .OfRows(x.Length, functions.Length, x.Select(xi => functions.Select(f => f(xi))))
- .QR().Solve(new DenseVector(y))
- .ToArray();
+ return MultipleRegression.QR(x.Select(xi => functions.Select(f => f(xi)).ToArray()).ToArray(), y);
}
///
@@ -165,10 +126,7 @@ namespace MathNet.Numerics
///
public static double[] LinearGeneric(T[] x, double[] y, params Func[] functions)
{
- return DenseMatrix
- .OfRows(x.Length, functions.Length, x.Select(xi => functions.Select(f => f(xi))))
- .QR().Solve(new DenseVector(y))
- .ToArray();
+ return MultipleRegression.QR(x.Select(xi => functions.Select(f => f(xi)).ToArray()).ToArray(), y);
}
///
diff --git a/src/Numerics/LinearRegression/MultipleRegression.cs b/src/Numerics/LinearRegression/MultipleRegression.cs
new file mode 100644
index 00000000..40655644
--- /dev/null
+++ b/src/Numerics/LinearRegression/MultipleRegression.cs
@@ -0,0 +1,169 @@
+//
+// Math.NET Numerics, part of the Math.NET Project
+// http://numerics.mathdotnet.com
+// http://github.com/mathnet/mathnet-numerics
+// http://mathnetnumerics.codeplex.com
+//
+// Copyright (c) 2009-2013 Math.NET
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using MathNet.Numerics.LinearAlgebra;
+
+namespace MathNet.Numerics.LinearRegression
+{
+ public static class MultipleRegression
+ {
+ ///
+ /// Find the model parameters β such that X*β with predictor X becomes as close to response Y as possible, with least squares residuals.
+ /// Uses the cholesky decomposition of the normal equations.
+ ///
+ /// Predictor matrix X
+ /// Response vector Y
+ /// Best fitting vector for model parameters β
+ public static Vector NormalEquations(Matrix x, Vector y) where T : struct, IEquatable, IFormattable
+ {
+ return x.TransposeThisAndMultiply(x).Cholesky().Solve(x.Transpose()*y);
+ }
+
+ ///
+ /// Find the model parameters β such that their linear combination with all predictor-arrays in X become as close to their response in Y as possible, with least squares residuals.
+ /// Uses the cholesky decomposition of the normal equations.
+ ///
+ /// List of predictor-arrays.
+ /// List of responses
+ /// True if an intercept should be added as first artificial perdictor value. Default = false.
+ /// Best fitting list of model parameters β for each element in the predictor-arrays.
+ public static T[] NormalEquations(T[][] x, T[] y, bool intercept = false) where T : struct, IEquatable, IFormattable
+ {
+ var predictor = Matrix.Build.DenseMatrixOfRowArrays(x);
+ if (intercept)
+ {
+ predictor = predictor.InsertColumn(0, Vector.Build.DenseVector(predictor.RowCount, Vector.One));
+ }
+ var response = Matrix.Build.DenseVector(y);
+ return predictor.TransposeThisAndMultiply(predictor).Cholesky().Solve(predictor.Transpose()*response).ToArray();
+ }
+
+ ///
+ /// Find the model parameters β such that their linear combination with all predictor-arrays in X become as close to their response in Y as possible, with least squares residuals.
+ /// Uses the cholesky decomposition of the normal equations.
+ ///
+ /// Sequence of predictor-arrays and their response.
+ /// True if an intercept should be added as first artificial perdictor value. Default = false.
+ /// Best fitting list of model parameters β for each element in the predictor-arrays.
+ public static T[] NormalEquations(IEnumerable> samples, bool intercept = false) where T : struct, IEquatable, IFormattable
+ {
+ var xy = samples.UnpackSinglePass();
+ return NormalEquations(xy.Item1, xy.Item2, intercept);
+ }
+
+ ///
+ /// Find the model parameters β such that X*β with predictor X becomes as close to response Y as possible, with least squares residuals.
+ /// Uses an orthogonal decomposition and is therefore more numerically stable than the normal equations but also slower.
+ ///
+ /// Predictor matrix X
+ /// Response vector Y
+ /// Best fitting vector for model parameters β
+ public static Vector QR(Matrix x, Vector y) where T : struct, IEquatable, IFormattable
+ {
+ return x.QR().Solve(y);
+ }
+
+ ///
+ /// Find the model parameters β such that their linear combination with all predictor-arrays in X become as close to their response in Y as possible, with least squares residuals.
+ /// Uses an orthogonal decomposition and is therefore more numerically stable than the normal equations but also slower.
+ ///
+ /// List of predictor-arrays.
+ /// List of responses
+ /// True if an intercept should be added as first artificial perdictor value. Default = false.
+ /// Best fitting list of model parameters β for each element in the predictor-arrays.
+ public static T[] QR(T[][] x, T[] y, bool intercept = false) where T : struct, IEquatable, IFormattable
+ {
+ var predictor = Matrix.Build.DenseMatrixOfRowArrays(x);
+ if (intercept)
+ {
+ predictor = predictor.InsertColumn(0, Vector.Build.DenseVector(predictor.RowCount, Vector.One));
+ }
+ return predictor.QR().Solve(Matrix.Build.DenseVector(y)).ToArray();
+ }
+
+ ///
+ /// Find the model parameters β such that their linear combination with all predictor-arrays in X become as close to their response in Y as possible, with least squares residuals.
+ /// Uses an orthogonal decomposition and is therefore more numerically stable than the normal equations but also slower.
+ ///
+ /// Sequence of predictor-arrays and their response.
+ /// True if an intercept should be added as first artificial perdictor value. Default = false.
+ /// Best fitting list of model parameters β for each element in the predictor-arrays.
+ public static T[] QR(IEnumerable> samples, bool intercept = false) where T : struct, IEquatable, IFormattable
+ {
+ var xy = samples.UnpackSinglePass();
+ return QR(xy.Item1, xy.Item2, intercept);
+ }
+
+ ///
+ /// Find the model parameters β such that X*β with predictor X becomes as close to response Y as possible, with least squares residuals.
+ /// Uses a singular value decomposition and is therefore more numerically stable (especially if ill-conditioned) than the normal equations or QR but also slower.
+ ///
+ /// Predictor matrix X
+ /// Response vector Y
+ /// Best fitting vector for model parameters β
+ public static Vector Svd(Matrix x, Vector y) where T : struct, IEquatable, IFormattable
+ {
+ return x.Svd().Solve(y);
+ }
+
+ ///
+ /// Find the model parameters β such that their linear combination with all predictor-arrays in X become as close to their response in Y as possible, with least squares residuals.
+ /// Uses a singular value decomposition and is therefore more numerically stable (especially if ill-conditioned) than the normal equations or QR but also slower.
+ ///
+ /// List of predictor-arrays.
+ /// List of responses
+ /// True if an intercept should be added as first artificial perdictor value. Default = false.
+ /// Best fitting list of model parameters β for each element in the predictor-arrays.
+ public static T[] Svd(T[][] x, T[] y, bool intercept = false) where T : struct, IEquatable, IFormattable
+ {
+ var predictor = Matrix.Build.DenseMatrixOfRowArrays(x);
+ if (intercept)
+ {
+ predictor = predictor.InsertColumn(0, Vector.Build.DenseVector(predictor.RowCount, Vector.One));
+ }
+ return predictor.Svd().Solve(Matrix.Build.DenseVector(y)).ToArray();
+ }
+
+ ///
+ /// Find the model parameters β such that their linear combination with all predictor-arrays in X become as close to their response in Y as possible, with least squares residuals.
+ /// Uses a singular value decomposition and is therefore more numerically stable (especially if ill-conditioned) than the normal equations or QR but also slower.
+ ///
+ /// Sequence of predictor-arrays and their response.
+ /// True if an intercept should be added as first artificial perdictor value. Default = false.
+ /// Best fitting list of model parameters β for each element in the predictor-arrays.
+ public static T[] Svd(IEnumerable> samples, bool intercept = false) where T : struct, IEquatable, IFormattable
+ {
+ var xy = samples.UnpackSinglePass();
+ return Svd(xy.Item1, xy.Item2, intercept);
+ }
+ }
+}
diff --git a/src/Numerics/LinearRegression/SimpleRegression.cs b/src/Numerics/LinearRegression/SimpleRegression.cs
new file mode 100644
index 00000000..081e831d
--- /dev/null
+++ b/src/Numerics/LinearRegression/SimpleRegression.cs
@@ -0,0 +1,88 @@
+//
+// Math.NET Numerics, part of the Math.NET Project
+// http://numerics.mathdotnet.com
+// http://github.com/mathnet/mathnet-numerics
+// http://mathnetnumerics.codeplex.com
+//
+// Copyright (c) 2009-2013 Math.NET
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using MathNet.Numerics.Properties;
+
+namespace MathNet.Numerics.LinearRegression
+{
+ public static class SimpleRegression
+ {
+ ///
+ /// Least-Squares fitting the points (x,y) to a line y : x -> a+b*x,
+ /// returning its best fitting parameters as (a, b) tuple,
+ /// where a is the intercept and b the slope.
+ ///
+ /// Predictor (independent)
+ /// Response (dependent)
+ public static Tuple Fit(double[] x, double[] y)
+ {
+ if (x.Length != y.Length) throw new ArgumentException(Resources.ArgumentVectorsSameLength);
+ if (x.Length <= 1) throw new ArgumentException(string.Format(Resources.ArrayTooSmall, 2));
+
+ // First Pass: Mean (Less robust but faster than ArrayStatistics.Mean)
+ double mx = 0.0;
+ double my = 0.0;
+ for (int i = 0; i < x.Length; i++)
+ {
+ mx += x[i];
+ my += y[i];
+ }
+ mx /= x.Length;
+ my /= y.Length;
+
+ // Second Pass: Covariance/Variance
+ double covariance = 0.0;
+ double variance = 0.0;
+ for (int i = 0; i < x.Length; i++)
+ {
+ double diff = x[i] - mx;
+ covariance += diff*(y[i] - my);
+ variance += diff*diff;
+ }
+
+ var b = covariance/variance;
+ return new Tuple(my - b*mx, b);
+ }
+
+ ///
+ /// Least-Squares fitting the points (x,y) to a line y : x -> a+b*x,
+ /// returning its best fitting parameters as (a, b) tuple,
+ /// where a is the intercept and b the slope.
+ ///
+ /// Predictor-Response samples as tuples
+ public static Tuple Fit(IEnumerable> samples)
+ {
+ var xy = samples.UnpackSinglePass();
+ return Fit(xy.Item1, xy.Item2);
+ }
+ }
+}
diff --git a/src/Numerics/LinearRegression/Util.cs b/src/Numerics/LinearRegression/Util.cs
new file mode 100644
index 00000000..f1c2a85f
--- /dev/null
+++ b/src/Numerics/LinearRegression/Util.cs
@@ -0,0 +1,52 @@
+//
+// Math.NET Numerics, part of the Math.NET Project
+// http://numerics.mathdotnet.com
+// http://github.com/mathnet/mathnet-numerics
+// http://mathnetnumerics.codeplex.com
+//
+// Copyright (c) 2009-2013 Math.NET
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+
+namespace MathNet.Numerics.LinearRegression
+{
+ internal static class Util
+ {
+ public static Tuple UnpackSinglePass(this IEnumerable> samples)
+ {
+ var u = new List();
+ var v = new List();
+
+ foreach (var tuple in samples)
+ {
+ u.Add(tuple.Item1);
+ v.Add(tuple.Item2);
+ }
+
+ return new Tuple(u.ToArray(), v.ToArray());
+ }
+ }
+}
diff --git a/src/Numerics/LinearRegression/WeightedRegression.cs b/src/Numerics/LinearRegression/WeightedRegression.cs
new file mode 100644
index 00000000..d615ad21
--- /dev/null
+++ b/src/Numerics/LinearRegression/WeightedRegression.cs
@@ -0,0 +1,97 @@
+//
+// Math.NET Numerics, part of the Math.NET Project
+// http://numerics.mathdotnet.com
+// http://github.com/mathnet/mathnet-numerics
+// http://mathnetnumerics.codeplex.com
+//
+// Copyright (c) 2009-2013 Math.NET
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using MathNet.Numerics.LinearAlgebra;
+using MathNet.Numerics.LinearAlgebra.Storage;
+
+namespace MathNet.Numerics.LinearRegression
+{
+ public static class WeightedRegression
+ {
+ ///
+ /// Weighted Linear Regression using normal equations.
+ ///
+ public static Vector Weighted(Matrix x, Vector y, Matrix w) where T : struct, IEquatable, IFormattable
+ {
+ return x.TransposeThisAndMultiply(w * x).Cholesky().Solve(x.Transpose() * (w * y));
+ }
+
+ ///
+ /// Weighted Linear Regression using normal equations.
+ ///
+ /// True if an intercept should be added as first artificial perdictor value. Default = false.
+ public static T[] Weighted(T[][] x, T[] y, T[] w, bool intercept = false) where T : struct, IEquatable, IFormattable
+ {
+ var predictor = Matrix.Build.DenseMatrixOfRowArrays(x);
+ if (intercept)
+ {
+ predictor = predictor.InsertColumn(0, Vector.Build.DenseVector(predictor.RowCount, Vector.One));
+ }
+ var response = Matrix.Build.DenseVector(y);
+ var weights = Matrix.Build.DiagonalMatrix(new DiagonalMatrixStorage(predictor.RowCount, predictor.RowCount, w));
+ return predictor.TransposeThisAndMultiply(weights * predictor).Cholesky().Solve(predictor.Transpose() * (weights * response)).ToArray();
+ }
+
+ ///
+ /// Weighted Linear Regression using normal equations.
+ ///
+ /// True if an intercept should be added as first artificial perdictor value. Default = false.
+ public static T[] Weighted(IEnumerable> samples, T[] w, bool intercept = false) where T : struct, IEquatable, IFormattable
+ {
+ var xy = samples.UnpackSinglePass();
+ return Weighted(xy.Item1, xy.Item2, w, intercept);
+ }
+
+ ///
+ /// Locally-Weighted Linear Regression using normal equations.
+ ///
+ public static Vector Local(Matrix x, Vector y, Vector t, Func, Vector, T> kernel) where T : struct, IEquatable, IFormattable
+ {
+ // TODO: Kernel definition is a bit weird as it includes computing the difference norm
+ // We can make this more common once we change the norm to always be of type double around LA.
+
+ var w = Matrix.Build.DenseMatrix(x.RowCount, x.RowCount);
+ for (int i = 0; i < x.RowCount; i++)
+ {
+ w.At(i, i, kernel(t, x.Row(i)));
+ }
+ return Weighted(x, y, w);
+ }
+
+ public static Func, Vector, double> GaussianKernel(double radius)
+ {
+ // TODO: see above...
+ var d = -2.0*radius*radius;
+ return (t, x) => Math.Exp(Distance.SSD(x, t)/d);
+ }
+ }
+}
diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj
index 4a99efb3..80b7e2ee 100644
--- a/src/Numerics/Numerics.csproj
+++ b/src/Numerics/Numerics.csproj
@@ -132,6 +132,10 @@
+
+
+
+
diff --git a/src/UnitTests/FitTests.cs b/src/UnitTests/FitTests.cs
index 38e301d0..c2444ff6 100644
--- a/src/UnitTests/FitTests.cs
+++ b/src/UnitTests/FitTests.cs
@@ -45,9 +45,8 @@ namespace MathNet.Numerics.UnitTests
var y = x.Select(z => 4.0 - 1.5*z).ToArray();
var resp = Fit.Line(x, y);
- Assert.AreEqual(2, resp.Length);
- Assert.AreEqual(4.0, resp[0], 1e-12);
- Assert.AreEqual(-1.5, resp[1], 1e-12);
+ Assert.AreEqual(4.0, resp.Item1, 1e-12);
+ Assert.AreEqual(-1.5, resp.Item2, 1e-12);
var resf = Fit.LineFunc(x, y);
foreach (var z in Enumerable.Range(-3, 10))
@@ -66,9 +65,8 @@ namespace MathNet.Numerics.UnitTests
var y = new[] {4.986, 2.347, 2.061, -2.995, -2.352, -5.782};
var resp = Fit.Line(x, y);
- Assert.AreEqual(2, resp.Length);
- Assert.AreEqual(7.01013, resp[0], 1e-4);
- Assert.AreEqual(-2.08551, resp[1], 1e-4);
+ Assert.AreEqual(7.01013, resp.Item1, 1e-4);
+ Assert.AreEqual(-2.08551, resp.Item2, 1e-4);
var resf = Fit.LineFunc(x, y);
foreach (var z in Enumerable.Range(-3, 10))