/// <summary> /// Fits the data to an arbitrary parameterized function. /// </summary> /// <param name="function">The fit function.</param> /// <param name="start">An initial guess at the parameters.</param> /// <returns>A fit result containing the best-fitting function parameters /// and a χ<sup>2</sup> test of the quality of the fit.</returns> /// <exception cref="ArgumentNullException"><paramref name="function"/> or <paramref name="start"/> are <see langword="null"/>.</exception> /// <exception cref="InsufficientDataException">There are fewer data points than fit parameters.</exception> /// <exception cref="DivideByZeroException">The curvature matrix is singular, indicating that the data is independent of /// one or more parameters, or that two or more parameters are linearly dependent.</exception> public FitResult FitToFunction(Func <double[], T, double> function, double[] start) { if (function == null) { throw new ArgumentNullException(nameof(function)); } if (start == null) { throw new ArgumentNullException(nameof(start)); } // you can't do a fit with less data than parameters if (this.Count < start.Length) { throw new InsufficientDataException(); } /* * Func<IList<double>, double> function0 = (IList<double> x0) => { * double[] x = new double[x0.Count]; * x0.CopyTo(x, 0); * return(function(x)); * }; * MultiExtremum minimum0 = MultiFunctionMath.FindMinimum(function0, start); */ // create a chi^2 fit metric and minimize it FitMetric <T> metric = new FitMetric <T>(this, function); SpaceExtremum minimum = FunctionMath.FindMinimum(new Func <double[], double>(metric.Evaluate), start); // compute the covariance (Hessian) matrix by inverting the curvature matrix SymmetricMatrix A = 0.5 * minimum.Curvature(); CholeskyDecomposition CD = A.CholeskyDecomposition(); // should not return null if we were at a minimum if (CD == null) { throw new DivideByZeroException(); } SymmetricMatrix C = CD.Inverse(); // package up the results and return them TestResult test = new TestResult("ChiSquare", minimum.Value, TestType.RightTailed, new ChiSquaredDistribution(this.Count - minimum.Dimension)); FitResult fit = new FitResult(minimum.Location(), C, test); return(fit); }
/// <summary> /// Fits the data to an arbitrary parameterized function. /// </summary> /// <param name="function">The fit function.</param> /// <param name="start">An initial guess at the parameters.</param> /// <returns>A fit result containing the best-fitting function parameters /// and a χ<sup>2</sup> test of the quality of the fit.</returns> /// <exception cref="ArgumentNullException"><paramref name="function"/> or <paramref name="start"/> are <see langword="null"/>.</exception> /// <exception cref="InsufficientDataException">There are fewer data points than fit parameters.</exception> /// <exception cref="DivideByZeroException">The curvature matrix is singular, indicating that the data is independent of /// one or more parameters, or that two or more parameters are linearly dependent.</exception> public UncertainMeasurementFitResult FitToFunction(Func <double[], T, double> function, double[] start) { if (function == null) { throw new ArgumentNullException(nameof(function)); } if (start == null) { throw new ArgumentNullException(nameof(start)); } // you can't do a fit with less data than parameters if (this.Count < start.Length) { throw new InsufficientDataException(); } // create a chi^2 fit metric and minimize it FitMetric <T> metric = new FitMetric <T>(this, function); SpaceExtremum minimum = FunctionMath.FindMinimum(new Func <double[], double>(metric.Evaluate), start); // compute the covariance (Hessian) matrix by inverting the curvature matrix SymmetricMatrix A = 0.5 * minimum.Curvature(); CholeskyDecomposition CD = A.CholeskyDecomposition(); // should not return null if we were at a minimum if (CD == null) { throw new DivideByZeroException(); } SymmetricMatrix C = CD.Inverse(); // package up the results and return them TestResult test = new TestResult("χ²", minimum.Value, new ChiSquaredDistribution(this.Count - minimum.Dimension), TestType.RightTailed); ParameterCollection parameters = new ParameterCollection(NumberNames(start.Length), new ColumnVector(minimum.Location(), 0, 1, start.Length, true), C); return(new UncertainMeasurementFitResult(parameters, test)); }