/// <summary>
        /// 計算多變量管制圖的 Tsquare decomposition
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mean"></param>
        /// <param name="S"></param>
        /// <returns></returns>
        public static LinearAlgebra.Matrix <double> T2Decomposition(LinearAlgebra.Matrix <double> data, LinearAlgebra.Matrix <double> mean, LinearAlgebra.Matrix <double> S)
        {
            //mean 的 #column = #columns of data = #columns of covariance
            if (data.ColumnCount != mean.ColumnCount || data.ColumnCount != S.ColumnCount || mean.ColumnCount != S.ColumnCount)
            {
                throw new ArgumentException("矩陣的維度無法計算");
            }

            LinearAlgebra.Matrix <double> invS = S.Inverse();

            List <double> tsquare = new List <double>();

            for (int i = 0; i < data.RowCount; i++)
            {
                tsquare.Add(CalculateTSquare(data.Row(i).ToRowMatrix(), mean, invS));
            }
            List <double> decoValue = new List <double>();

            for (int c = 0; c < data.ColumnCount; c++)
            {
                LinearAlgebra.Matrix <double> subData = data.RemoveColumn(c);
                LinearAlgebra.Matrix <double> subMean = mean.RemoveColumn(c);
                LinearAlgebra.Matrix <double> subS    = S.RemoveColumn(c).RemoveRow(c);
                LinearAlgebra.Matrix <double> invSubS = subS.Inverse();
                for (int r = 0; r < data.RowCount; r++)
                {
                    decoValue.Add(tsquare[r] - CalculateTSquare(subData.Row(r).ToRowMatrix(), subMean, invSubS));
                }
            }
            LinearAlgebra.Matrix <double> m = LinearAlgebra.Matrix <double> .Build.DenseOfColumnMajor(data.RowCount, data.ColumnCount, decoValue);

            return(m);
        }
        public LinearAlgebra.Vector <double> solveEquations(LinearAlgebra.Matrix <double> stiffnessMatrix, LinearAlgebra.Vector <double> forceVector, List <int> boundaryDofs, List <double> boundaryConstraints)
        {
            int nDof = forceVector.Count;

            // Find all dofs where force is known
            List <int> allDofs = Enumerable.Range(0, nDof).ToList();

            List <int> unknownDofs = allDofs.Except(boundaryDofs).ToList();

            // Add the know displacements to the result
            LinearAlgebra.Vector <double> displacementVector = LinearAlgebra.Vector <double> .Build.Dense(nDof);

            for (int i = 0; i < boundaryDofs.Count; i++)
            {
                displacementVector[boundaryDofs[i]] = boundaryConstraints[i];
            }

            // Pick out part of matrix corresponding to known forces
            int nrUnknownDofs = unknownDofs.Count;

            LinearAlgebra.Matrix <double> unknownK = LinearAlgebra.Matrix <double> .Build.Dense(nrUnknownDofs, nrUnknownDofs);

            LinearAlgebra.Vector <double> knownForces = LinearAlgebra.Vector <double> .Build.Dense(unknownDofs.Count);

            for (int i = 0; i < unknownDofs.Count; i++)
            {
                for (int j = 0; j < unknownDofs.Count; j++)
                {
                    unknownK[i, j] = stiffnessMatrix[unknownDofs[i], unknownDofs[j]];
                }
                knownForces[i] = forceVector[unknownDofs[i]];
            }

            LinearAlgebra.Matrix <double> unkownKnownK = LinearAlgebra.Matrix <double> .Build.Dense(nrUnknownDofs, boundaryDofs.Count);


            for (int i = 0; i < unknownDofs.Count; i++)
            {
                for (int j = 0; j < boundaryDofs.Count; j++)
                {
                    unkownKnownK[i, j] = stiffnessMatrix[unknownDofs[i], boundaryDofs[j]];
                }
                knownForces[i] = forceVector[unknownDofs[i]];
            }

            // Solve for the unknown displacements
            LinearAlgebra.Vector <double> unknownDisplacements = unknownK.Inverse().Multiply(knownForces.Subtract(unkownKnownK.Multiply(LinearAlgebra.Vector <double> .Build.Dense(boundaryConstraints.ToArray()))));

            // Insert the calculated displacements
            for (int i = 0; i < unknownDofs.Count; i++)
            {
                displacementVector[unknownDofs[i]] = unknownDisplacements[i];
            }

            return(displacementVector);
        }