/// <summary>
        /// Tridiagonal matrix multiplication (in place) M * x
        /// M = ( diag_0  upper_0   0         0    )
        ///     ( lower_1 diag_1  upper_1     0    )
        ///     (   0     lower_2 diag_2   upper_2 )
        ///     (   0       0     lower_3  diag_3  )
        /// </summary>
        /// <param name="x"></param>
        /// <param name="lower"></param>
        /// <param name="diag"></param>
        /// <param name="upper"></param>
        public static unsafe void MultTridiagonal(this double[] x, double[] lower, double[] diag, double[] upper)
        {
            int n = x.Length;

            if (n == 0)
            {
                return;
            }
            ArrayCheck.EqualSize(n, x, lower, diag, upper);
            fixed(double *px = &x[0], plower = &lower[0], pdiag = &diag[0], pupper = &upper[0])
            {
                MultTridiagonal(px, n, plower, pdiag, pupper);
            }
        }
        /// <summary>
        /// Solve tridiagonal system (in place) M * x = y
        /// M = ( diag_0  upper_0   0         0    )
        ///     ( lower_1 diag_1  upper_1     0    )
        ///     (   0     lower_2 diag_2   upper_2 )
        ///     (   0       0     lower_3  diag_3  )
        /// </summary>
        /// <param name="y"></param>
        /// <param name="lower"></param>
        /// <param name="diag"></param>
        /// <param name="upper"></param>
        public static unsafe void SolveTridiagonal(this double[] y, double[] lower, double[] diag, double[] upper)
        {
            int n = y.Length;

            if (n == 0)
            {
                return;
            }
            ArrayCheck.EqualSize(n, y, lower, diag, upper);
            fixed(double *py = &y[0], plower = &lower[0], pdiag = &diag[0], pupper = &upper[0])
            {
                SolveTridiagonal(py, n, plower, pdiag, pupper);
            }
        }