/// <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 &#x3C7;<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 &#x3C7;<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));
        }