/// <summary>
        /// This function return the area under curve using Gauss Legendre rule
        /// </summary>
        /// <param name="function">Function. function for curve</param>
        /// <param name="lowerBound">double. lowerBound is lower bound of integral</param>
        /// <param name="upperBound">double. upperBound is lower bound of integral</param>
        /// <param name="accuracy">double. accuracy is the value of corvergence tolerance</param>
        /// <returns>The area under the curve</returns>
        public static double GaussLegendre(BaseFunction function,
            double lowerBound, double upperBound, double accuracy)
        {
            double dx = upperBound - lowerBound;
            double value = 1.0e+10;
            double oldValue;
            int numPoints = 10;
            int maxPoints = 10000;
            double[] x = new double[maxPoints];
            double[] w = new double[maxPoints];

            //  Compute the integral value adding points
            //  until the solution convergences or maxPoints
            //  is reached.

            do
            {

                //  Calculate the Gauss-Legendre weights and
                //  abscissas

                computeGaussWeights(x, w, numPoints);

                //  Compute the integral value by summing up the
                //  weights times the function value at each
                //  abscissa

                oldValue = value;

                value = 0.0;
                for (int i = 0; i < numPoints; ++i)
                {
                    value += w[i] * function.Value(lowerBound + x[i] * dx);
                }
                value *= dx;

                //  If the solution is convergences, return the
                //  value. Otherwise, double the points in the
                //  integration domain and try again.

                if (Math.Abs(value - oldValue) <=
                    accuracy * Math.Abs(oldValue))
                {
                    return value;
                }

                numPoints *= 2;
            } while (numPoints < maxPoints);
            //  Solution did not convergence
            return value; ;
        }
        /// <summary>
        /// This function return the area under curve using Simpson's rule
        /// </summary>
        /// <param name="function">Function. function for curve</param>
        /// <param name="lowerBound">double. lowerBound is lower bound of integral</param>
        /// <param name="upperBound">double. upperBound is lower bound of integral</param>
        /// <param name="accuracy">double. accuracy is the value of corvergence tolerance</param>
        /// <returns>The area under the curve</returns>
        public static double SimpsonsRule(BaseFunction function,
            double lowerBound, double upperBound, double accuracy)
        {
            double dx = upperBound - lowerBound;
            double value, oldValue, sum, scale;
            double valueSimpson, oldValueSimpson;
            int maxIter = 20;

            //  Set initial values for the trapezoidal
            //  method (value) and Simpson's rule (valueSimpson)

            value = 0.5 * dx * (function.Value(lowerBound) +
                           function.Value(upperBound));
            valueSimpson = double.MaxValue;

            //  Subdivide the integration range by adding more
            //  points. Recompute the extended trapezoidal value
            //  and the Simpson's rule value. If the Simpson's
            //  rule value convergences, return the value.

            for (int i = 0; i < maxIter; ++i)
            {
                sum = 0.0;
                scale = Math.Pow(0.5, i + 1);
                for (int j = 0; j < Math.Pow(2, i); ++j)
                {
                    sum += function.Value(
                    lowerBound + scale * (2 * j + 1.0) * dx);
                }

                oldValue = value;
                value = 0.5 * value + scale * dx * sum;
                oldValueSimpson = valueSimpson;
                valueSimpson = (4.0 * value - oldValue) / 3.0;

                if (Math.Abs(valueSimpson - oldValueSimpson) <=
                    accuracy * Math.Abs(oldValueSimpson))
                {
                    return valueSimpson;
                }
            }
            //  Solution did not convergence
            return value; ;
        }
        /// <summary>
        /// This function return the area under curve using trapezoidal rule
        /// </summary>
        /// <param name="function">Function. function for curve</param>
        /// <param name="lowerBound">double. lowerBound is lower bound of integral</param>
        /// <param name="upperBound">double. upperBound is lower bound of integral</param>
        /// <param name="accuracy">double. accuracy is the value of corvergence tolerance</param>
        /// <returns>The area under the curve</returns>
        public static double Trapezoidal(BaseFunction function,
            double lowerBound, double upperBound, double accuracy)
        {
            double dx = upperBound - lowerBound;
            double value, oldValue, sum, scale;
            int maxIter = 20;

            //  first, compute an value of the integral using
            //  the two-point trapezoidal rule.

            value = 0.5 * dx * (function.Value(lowerBound) +
                function.Value(upperBound));

            // Subdivide the integration range by adding more
            // points. Recompute the integral value each time.
            // If the solution convergences, return the value.

            for (int i = 0; i < maxIter; ++i)
            {
                sum = 0.0;
                scale = Math.Pow(0.5, i + 1);
                for (int j = 0; j < Math.Pow(2, i); ++j)
                {
                    sum += function.Value(lowerBound +
                        scale * (2 * j + 1.0) * dx);
                }

                oldValue = value;
                value = 0.5 * value + scale * dx * sum;

                if (Math.Abs(value - oldValue) <=
                    accuracy * Math.Abs(oldValue))
                {
                    return value;
                }
            }

            //  Solution did not convergence
            return value; ;
        }
        /// <summary>
        /// This function return the area under curve using MidPoint rule
        /// </summary>
        /// <param name="function">Function. function for curve</param>
        /// <param name="lowerBound">double. lowerBound is lower bound of integral</param>
        /// <param name="upperBound">double. upperBound is lower bound of integral</param>
        /// <param name="accuracy">double. accuracy is the value of corvergence tolerance</param>
        /// <returns>The area under the curve</returns>
        public static double MidPoint(BaseFunction function,
            double lowerBound, double upperBound, double accuracy)
        {
            double dx = upperBound - lowerBound;
            double value, oldValue, sum, temp;
            double scale = 1.0 / 3.0;
            int numPoints, numPairs;
            int maxIter = 20;

            //  Start with a two-point midpoint
            //  evaluation.

            value = 0.5 * dx * (function.Value(lowerBound + 0.25 * dx) +
                function.Value(upperBound - 0.25 * dx));

            //  Refine the solution by adding points to the
            //  integration domain. Each iteration adds three
            //  times as many points as the previous iteration.
            //  When the solution convergences, return the result.

            for (int i = 0; i < maxIter; ++i)
            {
                numPoints = 4 * (int)Math.Pow(3, i);
                numPairs = (numPoints - 2) / 2;
                temp = 1.0 / (3.0 * numPoints);

                //  Add the two endpoint values to the sum

                sum = function.Value(lowerBound + temp * dx) +
                    function.Value(upperBound - temp * dx);

                //  Add in each pair to the sum

                for (int j = 0; j < numPairs; ++j)
                {
                    sum = sum +
                    function.Value(lowerBound + (6 * j + 5) * temp * dx) +
                    function.Value(lowerBound + (6 * j + 7) * temp * dx);
                }

                oldValue = value;
                value = value / 3.0 + 0.5 * Math.Pow(scale, i + 1) * dx * sum;

                if (Math.Abs(value - oldValue) <=
                    accuracy * Math.Abs(oldValue))
                {
                    return value;
                }
            }
            //  Solution did not convergence
            return value; ;
        }