Init(
            IList <double> t,
            IList <double> x)
        {
            if (null == t)
            {
                throw new ArgumentNullException("t");
            }

            if (null == x)
            {
                throw new ArgumentNullException("x");
            }

            if (t.Count < 5)
            {
                throw new ArgumentOutOfRangeException("t");
            }

            if (t.Count != x.Count)
            {
                throw new ArgumentException(Properties.LocalStrings.ArgumentVectorsSameLengths, "x");
            }

            int n = t.Count;

            double[] tt = new double[n];
            t.CopyTo(tt, 0);
            double[] xx = new double[n];
            x.CopyTo(xx, 0);

            Sorting.Sort(tt, xx);

            /* Prepare W (weights), Diff (divided differences) */

            double[] w    = new double[n - 1];
            double[] diff = new double[n - 1];

            for (int i = 0; i < diff.Length; i++)
            {
                diff[i] = (xx[i + 1] - xx[i]) / (tt[i + 1] - tt[i]);
            }

            for (int i = 1; i < w.Length; i++)
            {
                w[i] = Math.Abs(diff[i] - diff[i - 1]);
            }

            /* Prepare Hermite interpolation scheme */

            double[] d = new double[n];

            for (int i = 2; i < d.Length - 2; i++)
            {
                if (!Number.AlmostZero(w[i - 1]) || !Number.AlmostZero(w[i + 1]))
                {
                    d[i] = ((w[i + 1] * diff[i - 1]) + (w[i - 1] * diff[i])) / (w[i + 1] + w[i - 1]);
                }
                else
                {
                    d[i] = (((tt[i + 1] - tt[i]) * diff[i - 1]) + ((tt[i] - tt[i - 1]) * diff[i])) / (tt[i + 1] - tt[i - 1]);
                }
            }

            d[0]     = DifferentiateThreePoint(tt[0], tt[0], xx[0], tt[1], xx[1], tt[2], xx[2]);
            d[1]     = DifferentiateThreePoint(tt[1], tt[0], xx[0], tt[1], xx[1], tt[2], xx[2]);
            d[n - 2] = DifferentiateThreePoint(tt[n - 2], tt[n - 3], xx[n - 3], tt[n - 2], xx[n - 2], tt[n - 1], xx[n - 1]);
            d[n - 1] = DifferentiateThreePoint(tt[n - 1], tt[n - 3], xx[n - 3], tt[n - 2], xx[n - 2], tt[n - 1], xx[n - 1]);

            /* Build Akima spline using Hermite interpolation scheme */

            _hermiteSpline.InitInternal(tt, xx, d);
        }
        Init(
            IList <double> t,
            IList <double> x,
            SplineBoundaryCondition leftBoundaryCondition,
            double leftBoundary,
            SplineBoundaryCondition rightBoundaryCondition,
            double rightBoundary
            )
        {
            if (null == t)
            {
                throw new ArgumentNullException("t");
            }

            if (null == x)
            {
                throw new ArgumentNullException("x");
            }

            if (t.Count < 2)
            {
                throw new ArgumentOutOfRangeException("t");
            }

            if (t.Count != x.Count)
            {
                throw new ArgumentException(Properties.Resources.ArgumentVectorsSameLengths, "x");
            }

            int n = t.Count;

            double[] tt = new double[n];
            t.CopyTo(tt, 0);
            double[] xx = new double[n];
            x.CopyTo(xx, 0);

            Sorting.Sort(tt, xx);

            // normalize special cases
            if ((n == 2) &&
                (leftBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated) &&
                (rightBoundaryCondition == SplineBoundaryCondition.ParabolicallyTerminated))
            {
                leftBoundaryCondition  = SplineBoundaryCondition.SecondDerivative;
                leftBoundary           = 0d;
                rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative;
                rightBoundary          = 0d;
            }

            if (leftBoundaryCondition == SplineBoundaryCondition.Natural)
            {
                leftBoundaryCondition = SplineBoundaryCondition.SecondDerivative;
                leftBoundary          = 0d;
            }

            if (rightBoundaryCondition == SplineBoundaryCondition.Natural)
            {
                rightBoundaryCondition = SplineBoundaryCondition.SecondDerivative;
                rightBoundary          = 0d;
            }

            double[] a1 = new double[n];
            double[] a2 = new double[n];
            double[] a3 = new double[n];
            double[] b  = new double[n];

            // Left Boundary
            switch (leftBoundaryCondition)
            {
            case SplineBoundaryCondition.ParabolicallyTerminated:
                a1[0] = 0;
                a2[0] = 1;
                a3[0] = 1;
                b[0]  = 2 * (xx[1] - xx[0]) / (tt[1] - tt[0]);
                break;

            case SplineBoundaryCondition.FirstDerivative:
                a1[0] = 0;
                a2[0] = 1;
                a3[0] = 0;
                b[0]  = leftBoundary;
                break;

            case SplineBoundaryCondition.SecondDerivative:
                a1[0] = 0;
                a2[0] = 2;
                a3[0] = 1;
                b[0]  = 3 * (xx[1] - xx[0]) / (tt[1] - tt[0]) - 0.5 * leftBoundary * (tt[1] - tt[0]);
                break;

            default:
                throw new NotSupportedException(Properties.Resources.InvalidLeftBoundaryCondition);
            }

            // Central Conditions
            for (int i = 1; i < tt.Length - 1; i++)
            {
                a1[i] = tt[i + 1] - tt[i];
                a2[i] = 2 * (tt[i + 1] - tt[i - 1]);
                a3[i] = tt[i] - tt[i - 1];
                b[i]  = 3 * (xx[i] - xx[i - 1]) / (tt[i] - tt[i - 1]) * (tt[i + 1] - tt[i]) + 3 * (xx[i + 1] - xx[i]) / (tt[i + 1] - tt[i]) * (tt[i] - tt[i - 1]);
            }

            // Right Boundary
            switch (rightBoundaryCondition)
            {
            case SplineBoundaryCondition.ParabolicallyTerminated:
                a1[n - 1] = 1;
                a2[n - 1] = 1;
                a3[n - 1] = 0;
                b[n - 1]  = 2 * (xx[n - 1] - xx[n - 2]) / (tt[n - 1] - tt[n - 2]);
                break;

            case SplineBoundaryCondition.FirstDerivative:
                a1[n - 1] = 0;
                a2[n - 1] = 1;
                a3[n - 1] = 0;
                b[n - 1]  = rightBoundary;
                break;

            case SplineBoundaryCondition.SecondDerivative:
                a1[n - 1] = 1;
                a2[n - 1] = 2;
                a3[n - 1] = 0;
                b[n - 1]  = 3 * (xx[n - 1] - xx[n - 2]) / (tt[n - 1] - tt[n - 2]) + 0.5 * rightBoundary * (tt[n - 1] - tt[n - 2]);
                break;

            default:
                throw new NotSupportedException(Properties.Resources.InvalidRightBoundaryCondition);
            }

            // Build Spline
            double[] dd = SolveTridiagonal(a1, a2, a3, b);
            _hermiteSpline.InitInternal(tt, xx, dd);
        }