public static MatrixNxN Transpose(MatrixNxN _A)
        {
            if (_A == null || !_A.is_valid)
            {
                return(_A);
            }

            int nR = _A.nr_rows;
            int nC = _A.nr_cols;
            int nE = _A.nr_entries;

            double[] vals     = _A.values;
            double[] new_vals = new double[nE];

            // a b c d e f -> a d b e c f
            //---------------------------
            // a b c -> a d
            // d e f    b e
            //          c f
            int counter = 0;

            for (int j = 0; j < nC; j++)
            {
                for (int i = j; i < nE && counter < nE; i += nC, counter++)
                {
                    new_vals[counter] = vals[i];
                }
            }
            return(new MatrixNxN(nC, nR, new_vals));
        }
        // A'x A
        public static MatrixNxN Squared(MatrixNxN _A)
        {
            if (_A == null || !_A.is_valid)
            {
                return(MatrixNxN.ONEVALUE);
            }

            int nR = _A.nr_rows;
            int nC = _A.nr_cols;
            int nE = _A.nr_entries;

            double[] vals = _A.values;
            double[] calc = new double[nC * nC];

            double[,] rowsA = new double[nR, nC];
            double[,] colsA = new double[nC, nR];

            // extract the rows of A
            for (int i = 0; i < nR; i++)
            {
                for (int j = 0; j < nC; j++)
                {
                    rowsA[i, j] = vals[i * nC + j];
                }
            }

            // extract the columns of A
            for (int j = 0; j < nC; j++)
            {
                for (int i = j, counter = 0; i < nE && counter < nR; i += nC, counter++)
                {
                    colsA[j, counter] = vals[i];
                }
            }

            // perform calculation
            for (int i = 0; i < nC; i++)
            {
                for (int j = 0; j < nC; j++)
                {
                    calc[i * nC + j] = 0;
                    for (int k = 0; k < nR; k++)
                    {
                        calc[i * nC + j] += colsA[i, k] * colsA[j, k];
                    }
                }
            }

            return(new MatrixNxN(nC, nC, calc));
        }